package com.ys.service.storage.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ys.config.MenuId;
import com.ys.config.MyConfig;
import com.ys.entity.base.TbCountry;
import com.ys.entity.base.TbFileInfo;
import com.ys.entity.logistics.TpAmazonAddress;
import com.ys.entity.storage.*;
import com.ys.entity.sys.TsUserChange;
import com.ys.entity.sys.YsCol;
import com.ys.enume.base.TbFileInfoEnum;
import com.ys.enume.base.TransactionTypeEnum;
import com.ys.enume.storage.*;
import com.ys.mapper.base.TbFileInfoMapper;
import com.ys.mapper.storage.*;
import com.ys.service.business.TcwAccountDetailedForCompanyService;
import com.ys.service.storage.*;
import com.ys.service.sys.CommonApiService;
import com.ys.service.sys.PdfService;
import com.ys.service.sys.UploadService;
import com.ys.util.CheckUtil;
import com.ys.util.FbaUtils;
import com.ys.util.FileUtilYs;
import com.ys.util.ToolUtil;
import com.ys.util.shiro.ShiroUtils;
import com.ys.vo.R;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

//物流计划单
@Service("tccLogisticsComprehensiveOrderService")
public class TccLogisticsComprehensiveOrderServiceImpl implements TccLogisticsComprehensiveOrderService {
	private static final Logger logger = LoggerFactory.getLogger(TccLogisticsComprehensiveOrderServiceImpl.class);

	@Autowired
	private CommonApiService<TccLogisticsComprehensive> commonApiService;

	@Autowired
	private CheckUtil checkUtil;

	@Autowired
	private StorageMapper storageMapper;

	@Autowired
	private TccLogisticsComprehensiveMapper tccLogisticsComprehensiveMapper;

	@Autowired
	private TcwAccountDetailedForCompanyService tcwAccountDetailedForCompanyService;

	@Autowired
	private TccLogisticsSadFileMapper tccLogisticsSadFileMapper;

	@Autowired
	private TbFileInfoMapper tbFileInfoMapper;

	@Autowired
	private TccLogisticsChannelDetailMapper tccLogisticsChannelDetailMapper;

	@Autowired
	private TccLogisticsDetailChannelFeeMapper tccLogisticsDetailChannelFeeMapper;

	@Autowired
	private TccLogisticsApiService tccLogisticsApiService;

	@Autowired
	private PdfService pdfService;



    /**
     * 物流计划单 = 》 新增物流订单
     * @param  tccLogisticsComprehensiveList 需要生成同一个物流订单的物流计划信息
     * @return 返回结果
     */
	@Override
	public R add(List<TccLogisticsComprehensive> tccLogisticsComprehensiveList)throws Exception{
		//****** 1、生成 物流订单号 ******
		String bid = commonApiService.getCommonNextBid(MenuId.TCC_LogisticsComprehensive_Order);

		//*** 保存物流渠道详情表信息：TCC_LogisticsChannelDetail
		//saveLogisticsChannelDetail(tccLogisticsComprehensiveList,bid);

		//****** 4、获取订单生成人、时间 ******
		final  String userId = ShiroUtils.getUserId();
		final Date thisDate = new Date();

		//物流订单单号填入
		tccLogisticsComprehensiveList.forEach(e->e.setLogOrderBid(bid));


		//按发票
		if(tccLogisticsComprehensiveList.get(0).getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value)) {
			//****** 2、生成订单时的相关计算 ******
			//计算物流费用详情
			List<TccLogisticsDetailChannelFee> feeList = countLogisticsDetailFee(tccLogisticsComprehensiveList);

			//根据发票号分组
			Map<String, List<TccLogisticsComprehensive>> groupsByStr = tccLogisticsComprehensiveList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
			//遍历
			groupsByStr.forEach((logInvoiceNo, listByInvoiceNo) -> {
				List<TccLogisticsDetailChannelFee> feeByInvoiceList = feeList.stream().filter(e->e.getLogInvoiceNo().equals(logInvoiceNo)).collect(Collectors.toList());;
				TccLogisticsDetailChannelFee feeInfo = feeByInvoiceList.get(0);
				//***物流发票计重（总） = 物流渠道费用详情内容
				BigDecimal logInvoiceWeight = feeInfo.getShipOrderWeight();
				//***物流发票费用（总） = 物流渠道费用详情内容
				BigDecimal logInvoiceCost = feeInfo.getLogisticsCost();

				List<TccFbaDeliverSon> tccFbaDeliverSonList = new ArrayList<>();
				for(TccLogisticsComprehensive item:listByInvoiceNo){
					//*** 物流发票箱数 = 箱号分类汇总--计数统计
					List<TccFbaDeliverSon> tccFbaDeliverSonListByOne = new TccFbaDeliverSon().setFbaDeliverItemId(item.getFbaDeliverItemId()).queryList();
					tccFbaDeliverSonList.addAll(tccFbaDeliverSonListByOne);
				}
				//按箱子编号去重
				Map<String, List<TccFbaDeliverSon>> groupsByBoxNo = tccFbaDeliverSonList.stream().collect(Collectors.groupingBy(e->e.getBoxNo()));


				//*** 物流销售费用（总） = FBA发货单&实际物流费（总）之和
				BigDecimal logInvoiceSalesFee = BigDecimal.ZERO;
				//根据发货单号去重
				Map<String, List<TccLogisticsComprehensive>> groupsByDeliverBid = listByInvoiceNo.stream().collect(Collectors.groupingBy(e->e.getFbaDeliverBid()));
				//遍历，填入去重的信息
				List<TccLogisticsComprehensive> listByDeliverBid = new ArrayList<>();
				groupsByDeliverBid.forEach((k, v) -> listByDeliverBid.add(v.get(0)));
				for(TccLogisticsComprehensive item:listByDeliverBid){
					TccFbaFeeDetails tccFbaFeeDetails = new TccFbaFeeDetails().setSourceBid(item.getFbaDeliverBid()).queryFirst();//根据发货单号获取实际物流运费
					logInvoiceSalesFee = logInvoiceSalesFee.add(tccFbaFeeDetails.getPriceTranPredict());
				}

				int logInvoiceBox = groupsByBoxNo.size();//物流发票箱数
				//*** 物流订单利润（总） = 物流销售费用（总）-物流发票费用（总）
				BigDecimal logOrderProfit = logInvoiceSalesFee.subtract(logInvoiceCost);
				BigDecimal logOrderProfitMargin = BigDecimal.ZERO;
				if(logInvoiceCost.compareTo(BigDecimal.ZERO)!=0){
					//*** 物流订单利润率（总） = 物流订单利润（总）/物流发票费用（总）*100%
					logOrderProfitMargin = (logOrderProfit.divide(logInvoiceCost,4,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)))
							.setScale(2, BigDecimal.ROUND_HALF_UP);//结果保留2位小数
				}else {
					throw new RuntimeException("计算有误，请核实");
				}


				int isFirst = 1;
				//信息填入
				for(TccLogisticsComprehensive tccLogisticsComprehensive:listByInvoiceNo){
					tccLogisticsComprehensive.setLogOrderBid(bid);//订单单号
					tccLogisticsComprehensive.setLogInvoiceBox(logInvoiceBox);//物流发票箱数
					tccLogisticsComprehensive.setLogOrderProfit(logOrderProfit);//物流订单利润（总）
					tccLogisticsComprehensive.setLogOrderProfitMargin(logOrderProfitMargin);//物流订单利润率（总）
					tccLogisticsComprehensive.setLogInvoiceWeight(logInvoiceWeight);//物流发票计重（总）
					tccLogisticsComprehensive.setLogInvoiceCost(logInvoiceCost);//物流发票费用（总）
					tccLogisticsComprehensive.setLogInvoiceSalesFee(logInvoiceSalesFee);//物流销售费用（总）
					tccLogisticsComprehensive.setOrderGenUser(userId);//物流订单生成操作人
					tccLogisticsComprehensive.setOrderGenTime(thisDate);//物流订单生成时间
					tccLogisticsComprehensive.setStatus(TccLogisticsComprehensiveEnum.Status.GENERATED.value);//订单状态
					tccLogisticsComprehensive.setIsFirstByInvoice(isFirst==1?1:0);//是否是同一发票中的第一条（0否1是）
					tccLogisticsComprehensive.setApiPlaceOrderStatus(TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.EMPTY.value);//api下单状态


					isFirst ++;
					//****** 5、生成C88文件管理表 ******
					//查询新增所需参数
					TccFbaDeliverItem tccFbaDeliverItem = new TccFbaDeliverItem().setId(tccLogisticsComprehensive.getFbaDeliverItemId()).queryFirst();
					TccFbaBoxUpInfo tccFbaBoxUpInfo = new TccFbaBoxUpInfo().setId(tccFbaDeliverItem.getFbaBoxUpInfoId()).queryFirst();
					TccFbaPlan tccFbaPlan = new TccFbaPlan().setBid(tccLogisticsComprehensive.getFbaPlanBid()).queryFirst();
					TccLogisticsChannelMaint tccLogisticsChannelMaint = new TccLogisticsChannelMaint().setId(tccLogisticsComprehensive.getLogChannelId()).queryFirst();

					//查询亚马逊仓库地址仓库区域
					TpAmazonAddress tpAmazonAddress = new TpAmazonAddress().setDestinationFulfillmentCenterId(tccFbaBoxUpInfo.getFbaWarehouse()).queryFirst();
					tccLogisticsComprehensive.setWarehouseArea(tpAmazonAddress.getWarehouseArea());

					//计算方数
					List<TccFbaBox> tccFbaBoxList = new TccFbaBox()
							.addLeftJoin("TCC_FbaBoxDetail B ON B.BoxId = A.Id")
							.where("B.FbaBoxUpInfoId = "+tccFbaDeliverItem.getFbaBoxUpInfoId())
							.queryList();
					//去重
					Map<String, List<TccFbaBox>> boxListByGroup = tccFbaBoxList.stream().collect(Collectors.groupingBy(e->e.getId().toString()));
					List<TccFbaBox> boxList = new ArrayList<>();
					//遍历，填入去重的信息
					boxListByGroup.forEach((k, v) -> boxList.add(v.get(0)));
					BigDecimal cubeNum = BigDecimal.ZERO;//总方数

					for(TccFbaBox tccFbaBox:boxList){
						cubeNum = cubeNum.add(tccFbaBox.getBoxLong().multiply(tccFbaBox.getBoxWide()).multiply(tccFbaBox.getBoxHigh()));
					}
					cubeNum = cubeNum.divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
					tccLogisticsComprehensive.setCubeNum(cubeNum);
					tccLogisticsComprehensiveMapper.update(tccLogisticsComprehensive);

					//填入并新增
					TccLogisticsSadFile tccLogisticsSadFile = new TccLogisticsSadFile();
					tccLogisticsSadFile.setLogisticsComprehensiveId(tccLogisticsComprehensive.getId());//物流表id（TCC_LogisticsComprehensive）
					tccLogisticsSadFile.setFbaNo(tccFbaBoxUpInfo.getFbaNo());//FBA编号
					tccLogisticsSadFile.setLogOrderBid(bid);//订单单号
					tccLogisticsSadFile.setLogInvoiceNo(tccLogisticsComprehensive.getLogInvoiceNo());//发票号
					tccLogisticsSadFile.setDeclareState(0);//申报状态（0未申报、1已申报）
					tccLogisticsSadFile.setVgsbm(tccFbaPlan.getVgsbm());//运营公司编码
					tccLogisticsSadFile.setLogisticsName(tccLogisticsComprehensive.getLogChannelName());//物流名称
					if(tccLogisticsChannelMaint!=null && tccLogisticsChannelMaint.getLogsticsWay()!=null) {
						tccLogisticsSadFile.setLogisticsService(tccLogisticsChannelMaint.getLogsticsWay());//物流服务商
					}
					if(tpAmazonAddress.getCountryCode()!=null)tccLogisticsSadFile.setCountryBid(tpAmazonAddress.getCountryCode());//国家编码
					tccLogisticsSadFile.setCountryBid(tccLogisticsChannelMaint.getCountry());
					tccLogisticsSadFileMapper.insert(tccLogisticsSadFile);
				}

			});
		}else{
			//根据发票号分组
			Map<String, List<TccLogisticsComprehensive>> groupsByStr = tccLogisticsComprehensiveList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
			//遍历
			groupsByStr.forEach((logInvoiceNo, listByInvoiceNo) -> {

				List<TccFbaDeliverSon> tccFbaDeliverSonList = new ArrayList<>();
				for(TccLogisticsComprehensive item:listByInvoiceNo){
					//*** 物流发票箱数 = 箱号分类汇总--计数统计
					List<TccFbaDeliverSon> tccFbaDeliverSonListByOne = new TccFbaDeliverSon().setFbaDeliverItemId(item.getFbaDeliverItemId()).queryList();
					tccFbaDeliverSonList.addAll(tccFbaDeliverSonListByOne);
				}
				//按箱子编号去重
				Map<String, List<TccFbaDeliverSon>> groupsByBoxNo = tccFbaDeliverSonList.stream().collect(Collectors.groupingBy(e->e.getBoxNo()));


				//*** 物流销售费用（总） = FBA发货单&实际物流费（总）之和
				//BigDecimal logInvoiceSalesFee = BigDecimal.ZERO;
				//根据发货单号去重
				Map<String, List<TccLogisticsComprehensive>> groupsByDeliverBid = listByInvoiceNo.stream().collect(Collectors.groupingBy(e->e.getFbaDeliverBid()));
				//遍历，填入去重的信息
				List<TccLogisticsComprehensive> listByDeliverBid = new ArrayList<>();
				groupsByDeliverBid.forEach((k, v) -> listByDeliverBid.add(v.get(0)));
//				for(TccLogisticsComprehensive item:listByDeliverBid){
//					TccFbaFeeDetails tccFbaFeeDetails = new TccFbaFeeDetails().setSourceBid(item.getFbaDeliverBid()).queryFirst();//根据发货单号获取实际物流运费
//					logInvoiceSalesFee = logInvoiceSalesFee.add(tccFbaFeeDetails.getPriceTranPredict());
//				}
				int logInvoiceBox = groupsByBoxNo.size();//物流发票箱数

				int isFirst = 1;
				//信息填入
				for(TccLogisticsComprehensive tccLogisticsComprehensive:listByInvoiceNo){
					tccLogisticsComprehensive.setLogOrderBid(bid);//订单单号
					tccLogisticsComprehensive.setLogInvoiceBox(logInvoiceBox);//物流发票箱数
//					tccLogisticsComprehensive.setLogOrderProfit(logOrderProfit);//物流订单利润（总）
//					tccLogisticsComprehensive.setLogOrderProfitMargin(logOrderProfitMargin);//物流订单利润率（总）
//					tccLogisticsComprehensive.setLogInvoiceWeight(logInvoiceWeight);//物流发票计重（总）
//					tccLogisticsComprehensive.setLogInvoiceCost(logInvoiceCost);//物流发票费用（总）
//					tccLogisticsComprehensive.setLogInvoiceSalesFee(logInvoiceSalesFee);//物流销售费用（总）
					tccLogisticsComprehensive.setOrderGenUser(userId);//物流订单生成操作人
					tccLogisticsComprehensive.setOrderGenTime(thisDate);//物流订单生成时间
					tccLogisticsComprehensive.setStatus(TccLogisticsComprehensiveEnum.Status.GENERATED.value);//订单状态
					tccLogisticsComprehensive.setIsFirstByInvoice(isFirst==1?1:0);//是否是同一发票中的第一条（0否1是）
					tccLogisticsComprehensive.setApiPlaceOrderStatus(TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.EMPTY.value);//api下单状态


					isFirst ++;
					//****** 5、生成C88文件管理表 ******
					//查询新增所需参数
					TccFbaDeliverItem tccFbaDeliverItem = new TccFbaDeliverItem().setId(tccLogisticsComprehensive.getFbaDeliverItemId()).queryFirst();
					TccFbaBoxUpInfo tccFbaBoxUpInfo = new TccFbaBoxUpInfo().setId(tccFbaDeliverItem.getFbaBoxUpInfoId()).queryFirst();
					TccFbaPlan tccFbaPlan = new TccFbaPlan().setBid(tccLogisticsComprehensive.getFbaPlanBid()).queryFirst();
					TccLogisticsChannelMaint tccLogisticsChannelMaint = new TccLogisticsChannelMaint().setId(tccLogisticsComprehensive.getLogChannelId()).queryFirst();

					//查询亚马逊仓库地址仓库区域
					TpAmazonAddress tpAmazonAddress = new TpAmazonAddress().setDestinationFulfillmentCenterId(tccFbaBoxUpInfo.getFbaWarehouse()).queryFirst();
					tccLogisticsComprehensive.setWarehouseArea(tpAmazonAddress.getWarehouseArea());

					//计算方数
					List<TccFbaBox> tccFbaBoxList = new TccFbaBox()
							.addLeftJoin("TCC_FbaBoxDetail B ON B.BoxId = A.Id")
							.where("B.FbaBoxUpInfoId = "+tccFbaDeliverItem.getFbaBoxUpInfoId())
							.queryList();
					//去重
					Map<String, List<TccFbaBox>> boxListByGroup = tccFbaBoxList.stream().collect(Collectors.groupingBy(e->e.getId().toString()));
					List<TccFbaBox> boxList = new ArrayList<>();
					//遍历，填入去重的信息
					boxListByGroup.forEach((k, v) -> boxList.add(v.get(0)));
					BigDecimal cubeNum = BigDecimal.ZERO;//总方数

					for(TccFbaBox tccFbaBox:boxList){
						cubeNum = cubeNum.add(tccFbaBox.getBoxLong().multiply(tccFbaBox.getBoxWide()).multiply(tccFbaBox.getBoxHigh()));
					}
					cubeNum = cubeNum.divide(new BigDecimal(1000),2,BigDecimal.ROUND_HALF_UP);
					tccLogisticsComprehensive.setCubeNum(cubeNum);


					tccLogisticsComprehensiveMapper.update(tccLogisticsComprehensive);

					//填入并新增
					TccLogisticsSadFile tccLogisticsSadFile = new TccLogisticsSadFile();
					tccLogisticsSadFile.setLogisticsComprehensiveId(tccLogisticsComprehensive.getId());//物流表id（TCC_LogisticsComprehensive）
					tccLogisticsSadFile.setFbaNo(tccFbaBoxUpInfo.getFbaNo());//FBA编号
					tccLogisticsSadFile.setLogOrderBid(bid);//订单单号
					tccLogisticsSadFile.setLogInvoiceNo(tccLogisticsComprehensive.getLogInvoiceNo());//发票号
					tccLogisticsSadFile.setDeclareState(0);//申报状态（0未申报、1已申报）
					tccLogisticsSadFile.setVgsbm(tccFbaPlan.getVgsbm());//运营公司编码
					tccLogisticsSadFile.setLogisticsName(tccLogisticsComprehensive.getLogChannelName());//物流名称
					if(tccLogisticsChannelMaint!=null && tccLogisticsChannelMaint.getLogsticsWay()!=null) {
						tccLogisticsSadFile.setLogisticsService(tccLogisticsChannelMaint.getLogsticsWay());//物流服务商
					}
					if(tpAmazonAddress.getCountryCode()!=null)tccLogisticsSadFile.setCountryBid(tpAmazonAddress.getCountryCode());//国家编码
					tccLogisticsSadFileMapper.insert(tccLogisticsSadFile);
				}

			});
		}



		return R.ok();

	}


	//计算物流费用详情
	public List<TccLogisticsDetailChannelFee> countLogisticsDetailFee(List<TccLogisticsComprehensive> tccLogisticsComprehensiveList) throws Exception{

		//获取物流渠道信息
		//TccLogisticsChannelDetail tccLogisticsChannelDetail = new TccLogisticsChannelDetail().setBid(bid).queryFirst();
		TccLogisticsChannelMaint tccLogisticsChannelMaintByMain = new TccLogisticsChannelMaint().setId(tccLogisticsComprehensiveList.get(0).getLogChannelId()).queryFirst();

		if (tccLogisticsChannelMaintByMain.getCoefficientWeight() == 0) {
			tccLogisticsChannelMaintByMain.setCoefficientWeight(5000);
		} else {
			tccLogisticsChannelMaintByMain.setCoefficientWeight(6000);
		}

		List<TccLogisticsDetailChannelFee> feeList = new ArrayList<>();


		//实重（kg）
		BigDecimal weightRealByOrder = BigDecimal.ZERO;
		//抛重（kg）
		BigDecimal weightVolByOrder = BigDecimal.ZERO;
		//计重（kg）
		BigDecimal weightCalByOrder = BigDecimal.ZERO;

		boolean countByReal = false;

		//按订单计算
		if(tccLogisticsComprehensiveList.get(0).getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_ORDER.value)){
			//获取FBA信息
			String fbaDeliverItemIds = "";
			for (TccLogisticsComprehensive item :tccLogisticsComprehensiveList){
				if ("".equals(fbaDeliverItemIds)) {
					fbaDeliverItemIds =  item.getFbaDeliverItemId().toString();
				}else {
					fbaDeliverItemIds = fbaDeliverItemIds + "," + item.getFbaDeliverItemId().toString();
				}
			}
			//箱子数据
			List<TccTicketBox> tccTicketBoxeList = storageMapper.getTicketBoxListByOrder(fbaDeliverItemIds);
			//运输类型快递以外都是物流 0.快递|1.物流
			Integer transportation = 0;
			if (tccLogisticsChannelMaintByMain.getTransportationId() != 0) {
				transportation = 1;
			}

			for (TccTicketBox tccTicketBox : tccTicketBoxeList){
				//0.快递|1.物流
				if (transportation == 0) {
					//实重（kg）（拼） 所有箱---MAX（实重，单箱起重）先约分---在相加
					weightRealByOrder = weightRealByOrder.add(
							ruleReduction(tccLogisticsChannelMaintByMain, tccTicketBox.getBoxWeight())
									.max(tccLogisticsChannelMaintByMain.getWeightCalBySingle())
					);
					//抛重（kg）（拼） = 所有箱---MAX（抛重，单箱起重）先约分---在相加
					weightVolByOrder = weightVolByOrder.add(ruleReduction(tccLogisticsChannelMaintByMain, (tccTicketBox.getBoxLong().multiply(tccTicketBox.getBoxWide()).multiply(tccTicketBox.getBoxHigh()))
							.divide(new BigDecimal(tccLogisticsChannelMaintByMain.getCoefficientWeight()), 2, RoundingMode.HALF_UP)));
				}else {
					//实重（kg）（拼） =所有箱---MAX（实重，单箱起重）先相加---在约分
					weightRealByOrder = weightRealByOrder.add(
							tccTicketBox.getBoxWeight()).max(tccLogisticsChannelMaintByMain.getWeightCalBySingle()
					);
					//抛重（kg） （拼）= 所有箱---MAX（抛重，单箱起重）先相加---在约分
					weightVolByOrder = weightVolByOrder.add((tccTicketBox.getBoxLong().multiply(tccTicketBox.getBoxWide()).multiply(tccTicketBox.getBoxHigh()))
							.divide(new BigDecimal(tccLogisticsChannelMaintByMain.getCoefficientWeight()), 2, RoundingMode.HALF_UP));
				}
			}

			//0.快递|1.物流
			if (transportation == 1) {
				//在约分
				weightRealByOrder = ruleReduction(tccLogisticsChannelMaintByMain,weightRealByOrder);
				weightVolByOrder = ruleReduction(tccLogisticsChannelMaintByMain,weightVolByOrder);
			}

			if(weightRealByOrder.compareTo(weightVolByOrder)>0){
				//取实重
				countByReal = true;
				weightCalByOrder = weightRealByOrder;
			}else {
				//取抛重
				countByReal = false;
				weightCalByOrder = weightVolByOrder;
			}
		}

		final boolean countIsByReal = countByReal;
		final BigDecimal weightReal = weightRealByOrder;//实重（kg）
		final BigDecimal weightVol = weightVolByOrder;//抛重（kg）
		final BigDecimal weightCal = weightCalByOrder;//计重（kg）

		//根据发票号分组
		Map<String, List<TccLogisticsComprehensive>> groupsByStr = tccLogisticsComprehensiveList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
		//遍历
		groupsByStr.forEach((logInvoiceNo, listByInvoiceNo) -> {

			TccLogisticsDetailChannelFee tccLogisticsDetailChannelFee = new TccLogisticsDetailChannelFee();
			TccLogisticsComprehensive logisticsComprehensiveByOne = listByInvoiceNo.get(0);

			TccLogisticsChannelMaint tccLogisticsChannelMaint = new TccLogisticsChannelMaint().setId(logisticsComprehensiveByOne.getLogChannelId()).queryFirst();

			TccLogisticsServiceProvider tccLogisticsServiceProvider = new TccLogisticsServiceProvider().setProviderBid(tccLogisticsChannelMaint.getProviderCode()).queryFirst();



			String fbaDeliverItemIds = "";
			for (TccLogisticsComprehensive item :listByInvoiceNo){
				if ("".equals(fbaDeliverItemIds)) {
					fbaDeliverItemIds =  item.getFbaDeliverItemId().toString();
				}else {
					fbaDeliverItemIds = fbaDeliverItemIds + "," + item.getFbaDeliverItemId().toString();
				}
			}



			//材质梯度
			List<TccLogisticsChannelMaintItemSon> czTdList = new TccLogisticsChannelMaintItemSon()
					.setMethodId(tccLogisticsChannelMaint.getId())
					.queryList();

			//运输类型快递以外都是物流 0.快递|1.物流
			Integer transportation = 0;
			if (tccLogisticsChannelMaintByMain.getTransportationId() != 0) {
				transportation = 1;
			}

			//箱子数据
			List<TccTicketBox> tccTicketBoxeList = storageMapper.getTicketBoxListByOrder(fbaDeliverItemIds);
			//获取品名信息
			List<TccTicketBrandName> tccTicketBrandNameList = storageMapper.getTccTicketBrandNameListByOrder(fbaDeliverItemIds);

			//实重（kg）（拼）
			BigDecimal weightRealPp = BigDecimal.ZERO;
			//抛重（kg）
			BigDecimal weightVolPp = BigDecimal.ZERO;
			//计重（kg）
			//BigDecimal weightCalPp = BigDecimal.ZERO;
			for (TccTicketBox tccTicketBox : tccTicketBoxeList){
				//0.快递|1.物流
				if (transportation == 0) {
					//实重（kg）（拼） 所有箱---MAX（实重，单箱起重）先约分---在相加
					weightRealPp = weightRealPp.add(
							ruleReduction(tccLogisticsChannelMaintByMain, tccTicketBox.getBoxWeight())
									.max(tccLogisticsChannelMaintByMain.getWeightCalBySingle())
					);
					//抛重（kg）（拼） = 所有箱---MAX（抛重，单箱起重）先约分---在相加
					weightVolPp = weightVolPp.add(ruleReduction(tccLogisticsChannelMaintByMain, (tccTicketBox.getBoxLong().multiply(tccTicketBox.getBoxWide()).multiply(tccTicketBox.getBoxHigh()))
							.divide(new BigDecimal(tccLogisticsChannelMaintByMain.getCoefficientWeight()), 2, RoundingMode.HALF_UP)));
				}else {
					//实重（kg）（拼） =所有箱---MAX（实重，单箱起重）先相加---在约分
					weightRealPp = weightRealPp.add(
							tccTicketBox.getBoxWeight()).max(tccLogisticsChannelMaintByMain.getWeightCalBySingle()
					);
					//抛重（kg） （拼）= 所有箱---MAX（抛重，单箱起重）先相加---在约分
					weightVolPp = weightVolPp.add((tccTicketBox.getBoxLong().multiply(tccTicketBox.getBoxWide()).multiply(tccTicketBox.getBoxHigh()))
							.divide(new BigDecimal(tccLogisticsChannelMaintByMain.getCoefficientWeight()), 2, RoundingMode.HALF_UP));
				}
			}

			//0.快递|1.物流
			if (transportation == 1) {
				//在约分
				weightRealPp = ruleReduction(tccLogisticsChannelMaintByMain,weightRealPp);
				weightVolPp = ruleReduction(tccLogisticsChannelMaintByMain,weightVolPp);
			}

			//计重（kg）（拼） = MAX【实重（kg）（拼），抛重（kg）（拼）】
			//weightCalPp = weightRealPp.max(weightVolPp);

			//品名数量（收费） = 品名数（参照商品品名）-免费品名数
			Integer numProName = tccTicketBrandNameList.size() - tccLogisticsChannelMaintByMain.getFreeProNameNum();
			numProName = numProName> 0 ? numProName: 0;


			//材质名称（中文）（拼）
			String czCnPp = "";
			String czEn = "";
			//材质费用拼
			BigDecimal czFeePp = BigDecimal.ZERO;
			for (TccTicketBrandName tccTicketBrandName : tccTicketBrandNameList) {
				boolean isTiDuGet = false;
				//判断是否是混合材质
				if (tccTicketBrandName.getNameMaterialCn().indexOf(",") == -1) {
					//赋值材质附加费(取最大值)
					for (int j = 0; j < czTdList.size(); j++) {
						if (czTdList.get(j).getMaterialNameCn().equals(tccTicketBrandName.getNameMaterialCn())) {
							if (czTdList.get(j).getAdditionalMaterialBilling().compareTo(czFeePp) > 0) {
								czFeePp = (czTdList.get(j).getAdditionalMaterialBilling());
								czCnPp = (czTdList.get(j).getMaterialNameCn());
								czEn =  (czTdList.get(j).getMaterialNameEn());
								isTiDuGet = true;
							}
						}
					}
				} else {
					String[] nameMaterialCnList = tccTicketBrandName.getNameMaterialCn().split(",");
					for (String nameMaterialCn : nameMaterialCnList) {
						for (int j = 0; j < czTdList.size(); j++) {
							if (czTdList.get(j).getMaterialNameCn().equals(nameMaterialCn)) {
								if (czTdList.get(j).getAdditionalMaterialBilling().compareTo(czFeePp) > 0) {
									czFeePp = (czTdList.get(j).getAdditionalMaterialBilling());
									czCnPp = (czTdList.get(j).getMaterialNameCn());
									czEn =  (czTdList.get(j).getMaterialNameEn());
									isTiDuGet = true;
								}
							}
						}
					}
				}
//				if(!isTiDuGet){
//					throw new RuntimeException("未查询到对应的梯度价，请核实");
//				}
			}


			tccLogisticsDetailChannelFee.setBid(logisticsComprehensiveByOne.getLogOrderBid());//物流订单号
			tccLogisticsDetailChannelFee.setLogInvoiceNo(logInvoiceNo);//发票号
			tccLogisticsDetailChannelFee.setBidFbaDelivery(logisticsComprehensiveByOne.getFbaDeliverBid());//FBA发货单号
			tccLogisticsDetailChannelFee.setLogsticsChannelName(tccLogisticsChannelMaintByMain.getLogsticsChannelName());//物流渠道名称
			tccLogisticsDetailChannelFee.setFreightMethod(logisticsComprehensiveByOne.getFreightMethod());//运费计算方式

			tccLogisticsDetailChannelFee.setDeliveryActualWeight(weightRealPp);//发票实重（kg）
			tccLogisticsDetailChannelFee.setShipOrderThrowWeight(weightVolPp);//发票抛重（kg）

			tccLogisticsDetailChannelFee.setProductNameNum(tccTicketBrandNameList.size());//品名数量
			tccLogisticsDetailChannelFee.setProductFeeNum(numProName);//品名收费数量
			BigDecimal totalAmount = (tccLogisticsChannelMaintByMain.getAdditionalStandardAmount().multiply(new BigDecimal(numProName)))
					.setScale(2,BigDecimal.ROUND_HALF_UP);
			tccLogisticsDetailChannelFee.setEstimatSurcharge(totalAmount);//预估品名附加费（￥）

			tccLogisticsDetailChannelFee.setMaterialChargeable(czCnPp);//收费材质名称
			tccLogisticsDetailChannelFee.setAdditionalMaterial(czFeePp);//材质附加计费（￥/kg）

			tccLogisticsDetailChannelFee.setClearanceOpeAmount(tccLogisticsChannelMaintByMain.getClearanceOpeAmount());//清关服务费(￥)

			//目的地
			List<TccAdditionalBillingMaint> tccAdditionalBillingMaintList = new TccAdditionalBillingMaint().setMethodId(tccLogisticsChannelMaint.getId()).queryList();

			TccFbaBoxUpInfo tccFbaBoxUpInfo = new TccFbaBoxUpInfo()
					.addLeftJoin("TCC_FbaDeliverItem B ON B.FbaBoxUpInfoId = A.Id")
					.where("B.Id = "+logisticsComprehensiveByOne.getFbaDeliverItemId())
					.queryFirst();
			//目的地
			String finalWarehouse = tccFbaBoxUpInfo.getFbaWarehouseAddr();
			//目的地附加计费（￥/kg）
			BigDecimal additionalBilling = BigDecimal.ZERO;
			List<TccAdditionalBillingMaint> tccAdditionalBillingListNew = tccAdditionalBillingMaintList.stream().filter(
					tccAdditionalBilling -> finalWarehouse.equals(tccAdditionalBilling.getWarehouseCode())
			).collect(Collectors.toList());
			TccAdditionalBillingMaint tccAdditionalBillingMaint = null;
			//目的地 仓库代码满足直接取 反之 取邮编首数字开头的比并且仓库为空
			if (tccAdditionalBillingListNew.size() != 0) {
				additionalBilling = tccAdditionalBillingListNew.get(0).getAdditionalBilling();
				tccAdditionalBillingMaint = tccAdditionalBillingListNew.get(0);
			} else {
				tccAdditionalBillingListNew = tccAdditionalBillingMaintList.stream().filter(tccAdditionalBilling ->
						(tccAdditionalBilling.getWarehouseCode() == null || tccAdditionalBilling.getWarehouseCode().equals("")) && tccAdditionalBilling.getFirstPostalCode()!=null && finalWarehouse.startsWith(tccAdditionalBilling.getFirstPostalCode())
				).collect(Collectors.toList());
				if (tccAdditionalBillingListNew.size() != 0) {
					additionalBilling = tccAdditionalBillingListNew.get(0).getAdditionalBilling();
					tccAdditionalBillingMaint = tccAdditionalBillingListNew.get(0);
				}
			}

			tccLogisticsDetailChannelFee.setAdditionalDestination(additionalBilling);//目的地附加计费（￥/kg）


			//发票计重（kg）
			BigDecimal weightCalPp;
			//运费计算方式 - 按发票
			if(logisticsComprehensiveByOne.getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value)) {
				//MAX【FBA实重（kg），FBA抛重（kg）】
				weightCalPp = weightRealPp.max(weightVolPp);
			}else {
				//运费计算方式 - 按订单
				if(countIsByReal){//按实重
					weightCalPp = weightRealPp;
				}else {//按抛重
					weightCalPp = weightVolPp;
				}
			}

			tccLogisticsDetailChannelFee.setShipOrderWeight(weightCalPp);//发票计重（kg）
			BigDecimal totalAmountByMaterial = (weightCalPp.multiply(czFeePp)).setScale(2,BigDecimal.ROUND_HALF_UP);
			tccLogisticsDetailChannelFee.setEstimatMaterialSurcharge(totalAmountByMaterial);//预估材质附加费（￥）

			//计重梯度+抛重梯度
			List<TccLogisticsChannelMaintItem> tccLogisticsChannelMaintItems = new TccLogisticsChannelMaintItem()
					.setMethodId(tccLogisticsChannelMaint.getId())
					.queryList();
			//计重梯度
			List<TccLogisticsChannelMaintItem> jzTdList = tccLogisticsChannelMaintItems.stream().filter(tccLogisticsChannelMaintItem ->
					TccLogisticsMethodItemEnum.LogisticsMethodType.JZTD.value.equals(tccLogisticsChannelMaintItem.getChannelMaintType())).collect(Collectors.toList());

			//梯度价对应的重量
			BigDecimal tdCountWeight;
			//运费计算方式 - 按发票
			if(logisticsComprehensiveByOne.getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value)) {
				tdCountWeight = weightCalPp;// = 发票实重
			}else{
				tdCountWeight = weightReal;// = 订单实重
			}
			//计重梯度价（￥/kg） 参照“计重”对应范围的梯度价
			List<TccLogisticsChannelMaintItem> tdjzPrice = jzTdList.stream().filter(tccLogisticsChannelMaintItem -> tdCountWeight.compareTo(tccLogisticsChannelMaintItem.getHeavySn()) >= 0
					&& tdCountWeight.compareTo(tccLogisticsChannelMaintItem.getHeavyEn()) <= 0).collect(Collectors.toList());

			//计重梯度价（￥/kg）
			BigDecimal jfFee = BigDecimal.ZERO;
			BigDecimal jfStart = BigDecimal.ZERO;
			BigDecimal jfEnd = BigDecimal.ZERO;
			if (tdjzPrice.size() != 0) {
				jfFee = tdjzPrice.get(0).getPrice();
				jfStart =tdjzPrice.get(0).getHeavySn(); //计重梯度开始
				jfEnd =tdjzPrice.get(0).getHeavyEn(); //计重梯度结束
			}else {
				throw new RuntimeException("未查询到对应的计重梯度，请核实");
			}
			tccLogisticsDetailChannelFee.setWeightGradientPrice(jfFee);//计重梯度价（￥/kg）


			//按订单
			if(logisticsComprehensiveByOne.getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_ORDER.value)) {
				tccLogisticsDetailChannelFee.setOrderWeight(weightCal);//订单计重（kg）
				tccLogisticsDetailChannelFee.setOrderActualWeight(weightReal);//订单实重（kg）
				tccLogisticsDetailChannelFee.setOrderThrowWeight(weightVol);//订单抛重（kg）
			}

			//实际附加费（￥） = 预估品名附加费（￥）+预估材质附加费（￥）
			BigDecimal actualAdditionalFee = totalAmount.add(totalAmountByMaterial);
			tccLogisticsDetailChannelFee.setActualAdditionalFee(actualAdditionalFee);

			//ActualWeightFee 实际计重费（￥）= FBA计重（kg）*【计重梯度价（￥/kg）+目的地附加计费（￥/kg）】
			BigDecimal actualWeightFee = (weightCalPp.multiply(jfFee.add(additionalBilling))).setScale(2,BigDecimal.ROUND_HALF_UP);
			tccLogisticsDetailChannelFee.setActualWeightFee(actualWeightFee);

			//LogisticsCost	 FBA物流费用（总）= 实际计重费（￥）+实际附加费（￥）+清关服务费(￥)
			BigDecimal logisticsCost = actualWeightFee.add(actualAdditionalFee).add(tccLogisticsDetailChannelFee.getClearanceOpeAmount());
			tccLogisticsDetailChannelFee.setLogisticsCost(logisticsCost);

			tccLogisticsDetailChannelFeeMapper.insert(tccLogisticsDetailChannelFee);
			feeList.add(tccLogisticsDetailChannelFee);


			//long logChannelId = logisticsComprehensiveByOne.getLogChannelId();//物流渠道id

			TccLogisticsChannelDetail tccLogisticsChannelDetail = JSON.parseObject(JSON.toJSONString(tccLogisticsChannelMaintByMain), TccLogisticsChannelDetail.class);
			tccLogisticsChannelDetail.setBid(logisticsComprehensiveByOne.getLogOrderBid());//物流订单号
			tccLogisticsChannelDetail.setBidFbaDelivery(logisticsComprehensiveByOne.getFbaDeliverBid());//FBA发货单号
			tccLogisticsChannelDetail.setLogInvoiceNo(logisticsComprehensiveByOne.getLogInvoiceNo());//发票号
			tccLogisticsChannelDetail.setFreightMethod(logisticsComprehensiveByOne.getFreightMethod());//运费计算方式
			tccLogisticsChannelDetail.setJfStart(jfStart);//计重梯度开始
			tccLogisticsChannelDetail.setJfEnd(jfEnd);//计重梯度结束
			tccLogisticsChannelDetail.setJfFee(jfFee);//计重梯度计费
			tccLogisticsChannelDetail.setCzCn(czCnPp);	//材质附加开始
			tccLogisticsChannelDetail.setCzEn(czEn);	//材质附加结束
			tccLogisticsChannelDetail.setCzFee(czFeePp);	//材质附加计费
			tccLogisticsChannelDetail.setProviderName(tccLogisticsServiceProvider.getName());//物流服务商名称

			if(tccAdditionalBillingMaint!=null){
				tccLogisticsChannelDetail.setWarehouseArea(tccAdditionalBillingMaint.getWarehouseArea());	//仓库区域
				tccLogisticsChannelDetail.setFirstPostalCode(tccAdditionalBillingMaint.getFirstPostalCode());//邮编首数字
				tccLogisticsChannelDetail.setWarehouseCode(tccAdditionalBillingMaint.getWarehouseCode());//仓库代码
			}
			tccLogisticsChannelDetail.setAdditionalBilling(additionalBilling);	//目的地附加计费（￥/kg）

			//DestinationCountryName		目的国家名称
			tccLogisticsChannelDetailMapper.insert(tccLogisticsChannelDetail);
		});

		return feeList;

	}



//
//	//保存物流渠道详情表信息：TCC_LogisticsChannelDetail
//	public void saveLogisticsChannelDetail(List<TccLogisticsComprehensive> tccLogisticsComprehensiveList,String bid) throws Exception{
//
//		//根据发票号去重
//		Map<String, List<TccLogisticsComprehensive>> groupsByStr = tccLogisticsComprehensiveList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
//		List<TccLogisticsComprehensive> groupAfterList = new ArrayList<>();
//		//遍历，填入去重的信息
//		groupsByStr.forEach((k, v) -> groupAfterList.add(v.get(0)));
//
//		for(TccLogisticsComprehensive tccLogisticsComprehensive:groupAfterList) {
//			long logChannelId = tccLogisticsComprehensive.getLogChannelId();//物流渠道id
//			//获取物流渠道母表信息
//			TccLogisticsChannelMaint tccLogisticsChannelMaint = new TccLogisticsChannelMaint().setId(logChannelId).queryFirst();
//			//获取对应着子表信息
//			List<TccLogisticsChannelMaintItem> maintItemList = new TccLogisticsChannelMaintItem().setMethodId(logChannelId).queryList();
//			List<TccLogisticsChannelMaintItemSon> maintItemSonList = new TccLogisticsChannelMaintItemSon().setMethodId(logChannelId).queryList();
//
//			TccLogisticsChannelDetail tccLogisticsChannelDetail = JSON.parseObject(JSON.toJSONString(tccLogisticsChannelMaint), TccLogisticsChannelDetail.class);
//			tccLogisticsChannelDetail.setBid(bid);//物流订单号
//			tccLogisticsChannelDetail.setBidFbaDelivery(tccLogisticsComprehensive.getLogOrderBid());//FBA发货单号
//			tccLogisticsChannelDetail.setLogInvoiceNo(tccLogisticsComprehensive.getLogInvoiceNo());//发票号
//			tccLogisticsChannelDetail.setFreightMethod(tccLogisticsComprehensive.getFreightMethod());//运费计算方式
//			tccLogisticsChannelDetailMapper.insert(tccLogisticsChannelDetail);
//
//			//保存子列表信息
//			for (TccLogisticsChannelMaintItem tccLogisticsChannelMaintItem : maintItemList) {
//				TccLogisticsChannelDetailItem tccLogisticsChannelDetailItem = JSON.parseObject(JSON.toJSONString(tccLogisticsChannelMaintItem), TccLogisticsChannelDetailItem.class);
//				tccLogisticsChannelDetailItem.setMethodId(tccLogisticsChannelDetail.getId());
//				tccLogisticsChannelDetailItemMapper.insert(tccLogisticsChannelDetailItem);
//			}
//			//保存子列表信息
//			for (TccLogisticsChannelMaintItemSon tccLogisticsChannelMaintItemSon : maintItemSonList) {
//				TccLogisticsChannelDetailItemSon tccLogisticsChannelDetailItemSon = JSON.parseObject(JSON.toJSONString(tccLogisticsChannelMaintItemSon), TccLogisticsChannelDetailItemSon.class);
//				tccLogisticsChannelDetailItemSon.setMethodId(tccLogisticsChannelDetail.getId());
//				tccLogisticsChannelDetailItemSonMapper.insert(tccLogisticsChannelDetailItemSon);
//			}
//		}
//	}


	/**
	 * 确认下单
	 * @param logInvoiceNo 发票号
	 */
	@Override
	@Transactional(timeout=120,propagation= Propagation.REQUIRES_NEW)
	public R confirm(String logInvoiceNo)throws Exception{

		List<TccLogisticsComprehensive> doConfirmList = new TccLogisticsComprehensive().setLogInvoiceNo(logInvoiceNo).queryList();
		if(doConfirmList==null || doConfirmList.size()<=0){
			return R.error("未找到要确认下单的信息");
		}
		//获取可以确认下单的状态
		List<TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus> getConfirmStatusList = TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getConfirmStatus();

		//验证信息
		for(TccLogisticsComprehensive doConfirm:doConfirmList){
			TccFbaDeliverItem tccFbaDeliverItem = new TccFbaDeliverItem().setId(doConfirm.getFbaDeliverItemId()).queryFirst();
			TccFbaBoxUpInfo tccFbaBoxUpInfo = new TccFbaBoxUpInfo().setId(tccFbaDeliverItem.getFbaBoxUpInfoId()).queryFirst();

			if(doConfirm.getLogInvoiceWeight()==null || doConfirm.getLogInvoiceWeight().compareTo(BigDecimal.ZERO)==0){
				return R.error("还未进行按单收费核算，无法确认下单；");
			}

			//验证API下单状态 ，只有：空，成功（匹配） 才可过
			if(!TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.checkStatus(getConfirmStatusList,doConfirm.getApiPlaceOrderStatus())){
				return R.error("FBA编码："+tccFbaBoxUpInfo.getFbaNo()+"，API下单状态只有："+TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getNameStrByList(getConfirmStatusList)+"，才可进行确认下单！");
			}

			if(checkUtil.isNullByObject(doConfirm.getTrackingCode())){
				return R.error("FBA编码："+tccFbaBoxUpInfo.getFbaNo()+"，物流渠道追踪编码未导入");
			}
//			if(checkUtil.isNullByObject(doConfirm.getLenEncoding())){
//				return R.error("FBA编码："+tccFbaBoxUpInfo.getFbaNo()+"，IEN编码未导入");
//			}
			TccLogisticsSadFile tccLogisticsSadFile = new TccLogisticsSadFile().setFbaNo(tccFbaBoxUpInfo.getFbaNo()).queryFirst();
			if(tccLogisticsSadFile==null || tccLogisticsSadFile.getId()==null){
				return R.error("FBA编码："+tccFbaBoxUpInfo.getFbaNo()+"，C88文件信息未查询到");
			}
			int isImportFile = new TbFileInfo().setSourceType(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value).setSourceId(tccLogisticsSadFile.getId()).count();
			if(isImportFile<=0){
				return R.error("FBA编码："+tccFbaBoxUpInfo.getFbaNo()+"，C88文件信息未导入");
			}
		}



		String userId = ShiroUtils.getUserId();
		Date thisDate = new Date();
		//根据发票号去重
		Map<String, List<TccLogisticsComprehensive>> groupsByStr = doConfirmList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
		//遍历去重的信息
		groupsByStr.forEach((invoiceNo, doListByInvoiceNo) ->{
			TccLogisticsComprehensive doConfirm = doListByInvoiceNo.get(0);
			TccLogisticsChannelDetail tccLogisticsChannelDetail = new TccLogisticsChannelDetail().setLogInvoiceNo(invoiceNo).queryFirst();
			StringBuilder fbaDeliverBids = new StringBuilder();
			StringBuilder fbaNos = new StringBuilder();
			//根据发货单号去重
			Map<String, List<TccLogisticsComprehensive>> groupsByDeliverBid = doListByInvoiceNo.stream().collect(Collectors.groupingBy(e->e.getFbaDeliverBid()));
			//遍历去重的信息
			groupsByDeliverBid.forEach((fbaDeliverBid, doListByDeliverBid) ->{
				if(fbaDeliverBids.length()<=0){
					fbaDeliverBids.append(fbaDeliverBid);
				}else {
					fbaDeliverBids.append("、").append(fbaDeliverBid);
				}
			});
			for(TccLogisticsComprehensive item : doListByInvoiceNo){
				TccFbaBoxUpInfo tccFbaBoxUpInfo = new TccFbaBoxUpInfo()
						.addLeftJoin("TCC_FbaDeliverItem B ON B.FbaBoxUpInfoId = A.Id")
						.where("B.Id = "+item.getFbaDeliverItemId())
						.queryFirst();
				if(fbaNos.length()<=0){
					fbaNos.append(tccFbaBoxUpInfo.getFbaNo());
				}else {
					fbaNos.append("、").append(tccFbaBoxUpInfo.getFbaNo());
				}
			}

			//业务交易流水
			BigDecimal amount = doConfirm.getLogOrderProfit();//交易金额：物流订单利润（总）
			String remark = "物流发票号："+invoiceNo+"，FBA发货单："+fbaDeliverBids.toString()+"，FBA号："+fbaNos.toString();//备注

			R res1 = null;
			R res2 = null;
			try {
				res1 = tcwAccountDetailedForCompanyService.addTcwAccountDetailedForCompanyWithJc(
						"GS0899", "物流部（中间账户）",
						"GS0609", "物流部",
						TransactionTypeEnum.BusinessType.WLFW_TCYF.name,
						amount,
						doConfirm.getOrderGenTime(),
						new Date(),
						remark,
						doConfirm.getLogOrderBid(),//物流订单号
						new Date());

				res2 = tcwAccountDetailedForCompanyService.addTcwAccountDetailedForCompanyWithJc(
						"GS0609", "物流部",
						"GS0899", "物流部（中间账户）",
						TransactionTypeEnum.BusinessType.WLFW_TCYF.name,
						BigDecimal.ZERO.subtract(amount),
						doConfirm.getOrderGenTime(),
						new Date(),
						remark,
						doConfirm.getLogOrderBid(),//物流订单号
						new Date());
			} catch (Exception e) {
				logger.error("出错：",e.getMessage(),e);
				throw new RuntimeException(e.getMessage());
			}
			if(res1.getCode().equals(R.Code.FAILED.value)){
				throw new RuntimeException(res1.getMsg());
			}
			if(res2.getCode().equals(R.Code.FAILED.value)){
				throw new RuntimeException(res2.getMsg());
			}

			for(TccLogisticsComprehensive item : doListByInvoiceNo){

				//状态变成”物流订单待对账“
				item.setStatus(TccLogisticsComprehensiveEnum.Status.BERECONCILED.value);
				//物流确认下单时间
				//物流确认下单操作人
				item.setConfirmOrderUser(userId);
				item.setConfirmOrderTime(thisDate);
				//清关方式（0自税、1包税）
				if (tccLogisticsChannelDetail.getNameLogsticsClearance().equals(TccFbaLogisticsMethodEnum.NameLogsticsClearance.SELFTAX.value)){
					item.setTariffZfStatus(TccLogisticsComprehensiveEnum.TariffZfStatus.DUTYPENDING.value);
				}else {
					item.setTariffZfStatus(TccLogisticsComprehensiveEnum.TariffZfStatus.EMPTY.value);
				}
				tccLogisticsComprehensiveMapper.update(doConfirm);
			}

		});

		return R.ok();

	}





	//物流信息导入
	@Override
	public R locationImport(String rows,Long menuId) throws Exception{
		logger.info("导入的数据：\n" + rows);

		JSONArray detailList = JSON.parseArray(rows);
		for(int i=0;i<detailList.size();i++) {
			JSONObject info = detailList.getJSONObject(i);
			Map infoMap = JSONObject.parseObject(info.toString(), Map.class);
			//验证导入字段

			if (checkUtil.isNullByObject(infoMap.get("fbaNo"))) {
				return R.error("FBA编号为空");
			}

			if (checkUtil.isNullByObject(infoMap.get("trackingCode"))) {
				return R.error("物流渠道追踪编码为空");
			}

//			if (checkUtil.isNullByObject(infoMap.get("lenEncoding"))) {
//				return R.error("IEN编码为空");
//			}

			List<TccLogisticsComprehensive> logisticsComprehensiveList = new TccLogisticsComprehensive()
					.where("A.FbaNo = '"+infoMap.get("fbaNo").toString()+"'")
					.queryList();

			if(logisticsComprehensiveList!=null && logisticsComprehensiveList.size()>0){
				for(TccLogisticsComprehensive tccLogisticsComprehensive:logisticsComprehensiveList){
					if(!(tccLogisticsComprehensive.getStatus().equals(TccLogisticsComprehensiveEnum.Status.GENERATED.value)||tccLogisticsComprehensive.getStatus().equals(TccLogisticsComprehensiveEnum.Status.CANCEL.value))){
						return R.error("FBA编号："+TccLogisticsComprehensiveEnum.Status.getName(tccLogisticsComprehensive.getStatus())+"，不可再导入！");
					}
					tccLogisticsComprehensive.setTrackingCode(infoMap.get("trackingCode").toString());//物流渠道追踪编码
					//tccLogisticsComprehensive.setLenEncoding(infoMap.get("lenEncoding").toString());//IEN编码
					tccLogisticsComprehensiveMapper.update(tccLogisticsComprehensive);
				}
			}else {
				return R.error("FBA编号："+infoMap.get("fbaNo")+" 不存在");
			}
		}



		return R.ok();
	}



	/**
	 * 取消操作
	 * @param choooseDatas 选择的数据
	 */
	@Override
	public R doCancel(String choooseDatas)throws Exception{
		List<Map<String, Object>> chooseAllList = ToolUtil.jsonArrayToList(JSON.parseArray(choooseDatas));

		//获取可以确认下单的状态
		List<TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus> getApiConfirmStatusList = TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getDoCancelStatus();

		for(Map<String, Object> item:chooseAllList){
			//验证API下单状态 ，只有：空，成功（匹配） 才可过
			if(!TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.checkStatus(getApiConfirmStatusList,Integer.parseInt(item.get("apiPlaceOrderStatus").toString()))){
				return R.error("API下单状态只有："+TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getNameStrByList(getApiConfirmStatusList)+"，才可进行API下单！");
			}
		}

		StringBuilder resMsg = new StringBuilder();
		{
			//******** 获取“按物流订单”的数据 ********
			List<Map<String, Object>> chooseAllListByOrder = chooseAllList.stream().filter(e->Integer.parseInt(e.get("freightMethod").toString())== TccLogisticsComprehensiveEnum.FreightMethod.BY_ORDER.value).collect(Collectors.toList());
			if(chooseAllListByOrder.size()>0){
				//根据物流订单去重
				List<Map<String, Object>> chooseOrderList = ToolUtil.groupsByList(chooseAllListByOrder,e->e.get("logOrderBid").toString());
				for(Map<String, Object> item:chooseOrderList){
					String logOrderBid = item.get("logOrderBid").toString();
					R res = cancelByOrder(logOrderBid);
					if(res.getCode().equals(R.Code.FAILED.value)){
						resMsg.append("物流订单号【").append(logOrderBid).append("】取消失败：").append(res.getMsg()).append("</br>");
					}
				}
			}
		}

		{
			//******** 获取“按物流发票”的数据 ********
			List<Map<String, Object>> chooseAllListByInvoice = chooseAllList.stream().filter(e->Integer.parseInt(e.get("freightMethod").toString())== TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value).collect(Collectors.toList());
			if(chooseAllListByInvoice.size()>0){
				//根据发票号去重
				List<Map<String, Object>> chooseInvoiceList = ToolUtil.groupsByList(chooseAllListByInvoice,e->e.get("logInvoiceNo").toString());
				for(Map<String, Object> item:chooseInvoiceList){
					String logInvoiceNo = item.get("logInvoiceNo").toString();
					R res = cancelByInvoice(logInvoiceNo);
					if(res.getCode().equals(R.Code.FAILED.value)){
						resMsg.append("物流发票号【").append(logInvoiceNo).append("】取消失败：").append(res.getMsg()).append("</br>");
					}
				}
			}
		}

		if(resMsg.length()>0){
			return R.ok(resMsg);
		}else {
			return R.ok();
		}
	}

	/**
	 * 按订单号取消
	 * @param logOrderBid 物流订单号
	 */
	public R cancelByOrder(String logOrderBid)throws Exception{
		storageMapper.updateSetNullByLogisticsComprehensiveWithLogOrderBid(logOrderBid, TccLogisticsComprehensiveEnum.Status.EMPTY.value);
		//删除C88文件管理表信息
		storageMapper.delLogisticsSadFileByLogOrderBid(logOrderBid);

		//FBA完成成单状态修改成待发货
		List<TccLogisticsComprehensive> orderList = new TccLogisticsComprehensive().setLogOrderBid(logOrderBid).queryList();
		for(TccLogisticsComprehensive tccLogisticsComprehensive:orderList){
			storageMapper.updateTccFbaDeliverStateByLogisticsOrder(TccFbaDeliverEnum.Status.READYSHIPMENT.value,tccLogisticsComprehensive.getFbaDeliverBid());
		}


		return R.ok();
	}

	/**
	 * 按发票号取消
	 * @param logInvoiceNo 发票号
	 */
	public R cancelByInvoice(String logInvoiceNo)throws Exception{
		storageMapper.updateSetNullByLogisticsComprehensiveWithLogInvoiceNo(logInvoiceNo, TccLogisticsComprehensiveEnum.Status.EMPTY.value);
		//删除C88文件管理表信息
		storageMapper.delLogisticsSadFileByLogInvoiceNo(logInvoiceNo);

		//FBA完成成单状态修改成待发货
		List<TccLogisticsComprehensive> orderList = new TccLogisticsComprehensive().setLogInvoiceNo(logInvoiceNo).queryList();
		for(TccLogisticsComprehensive tccLogisticsComprehensive:orderList){
			storageMapper.updateTccFbaDeliverStateByLogisticsOrder(TccFbaDeliverEnum.Status.READYSHIPMENT.value,tccLogisticsComprehensive.getFbaDeliverBid());
		}
		return R.ok();
	}






	/**
	 * 批量导入C88文件
	 */
	@Override
	public R saveC88FileByBatch(JSONArray detailJA)throws Exception{
		logger.info("批量导入C88文件的数据：\n"+detailJA);
		List<Map<String, Object>> fileList = ToolUtil.jsonArrayToList(detailJA);

		//获取主表信息
		List<TccLogisticsSadFile> tccLogisticsSadFileList = new TccLogisticsSadFile().queryList();

		//根据FBA编码分组
		Map<String, List<Map<String, Object>>> groupsByFbaNo = fileList.stream().collect(Collectors.groupingBy(e->e.get("fbaNo").toString()));
		//遍历，填入去重的信息
		groupsByFbaNo.forEach((fbaNo, fileListByFbaNo) -> {
			Long userChangeId = null;
			//获取制单人信息
			TsUserChange tsUserChange = new TsUserChange().setUserId(ShiroUtils.getUserId()).setStatus(1).queryFirst();
			if(tsUserChange!=null){
				userChangeId = tsUserChange.getId();// 制单人信息
			}

			//根据FbaNo获取数据
			List<TccLogisticsSadFile> sadFileListByFbaNo = tccLogisticsSadFileList.stream().filter(e->e.getFbaNo().equals(fbaNo)).collect(Collectors.toList());
			if(sadFileListByFbaNo.size()>0){
				TccLogisticsSadFile tccLogisticsSadFile = sadFileListByFbaNo.get(0);
				for(Map<String, Object> fileInfo:fileListByFbaNo){
					TbFileInfo tbFileInfo = new TbFileInfo();
					tbFileInfo.setSourceType(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value);
					tbFileInfo.setSourceId(tccLogisticsSadFile.getId());
					tbFileInfo.setSourceCode("AnnexFile");
					tbFileInfo.setPreName(fileInfo.get("fileName").toString());//文件名，不含扩展名
					if(fileInfo.get("fileType")!=null) tbFileInfo.setSufName(fileInfo.get("fileType").toString());//文件后缀名，如.jpg
					if(fileInfo.get("fileType")!=null) tbFileInfo.setFileType(fileInfo.get("fileType").toString());//文件类型，如jpg
					if(fileInfo.get("fileSize")!=null && checkUtil.isInt(fileInfo.get("fileSize").toString())) tbFileInfo.setFileSize(Long.parseLong(fileInfo.get("fileSize").toString()));//文件大小，单位KB
					tbFileInfo.setFilePath(fileInfo.get("filePath").toString());//文件URL地址
					if(userChangeId!=null) tbFileInfo.setCreateChangeId(userChangeId);//创建人信息ID
					tbFileInfoMapper.insert(tbFileInfo);
				}

				//修改主表对应的数量
				int fileCount = new TbFileInfo()
						.setSourceType(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value)
						.setSourceId(tccLogisticsSadFile.getId())
						.count();
				if(fileCount>0){
					tccLogisticsSadFile.setAnnexFile(fileCount + "个C88文件");
					tccLogisticsSadFileMapper.update(tccLogisticsSadFile);
				}else {
					tccLogisticsSadFile.setAnnexFile("");
					tccLogisticsSadFileMapper.update(tccLogisticsSadFile);
				}

			}
		});

		return R.ok("导入成功！");
	}

	//按照约分规则约分
	private BigDecimal ruleReduction(TccLogisticsChannelMaint tccLogisticsChannelMaint,BigDecimal amount){
		//约分规则
		if (tccLogisticsChannelMaint.getDivisionalRule() == TccLogisticsMethodEnum.DivisionalRule.INTO1.value){
			amount = new BigDecimal(Math.ceil(amount.doubleValue()));
		}else if (tccLogisticsChannelMaint.getDivisionalRule() == TccLogisticsMethodEnum.DivisionalRule.INTO_05_1.value){
			amount = FbaUtils.precision(amount);
		}
		return amount;
	}



	//物流发票导出 - 按物流发票单导出
	@Override
	public R invoiceExport(List<Map<String, Object>> chooseList)throws Exception{
		StringBuffer logInvoiceNos = new StringBuffer();
		for(Map<String, Object> item:chooseList){
			if(checkUtil.isNotNullByObject(item.get("logInvoiceNo"))){
				if(logInvoiceNos.length()>0){
					logInvoiceNos.append(",");
				}
				logInvoiceNos.append("'").append(item.get("logInvoiceNo").toString()).append("'");
			}
		}

		//创建一个工作簿
		//SXSSFWorkbook wb = new SXSSFWorkbook(100);
		HSSFWorkbook wb = new HSSFWorkbook();
		Map<String, CellStyle> styles = createStyles(wb);

		CellStyle cellStyle = wb.createCellStyle();		//预设样式
		cellStyle.cloneStyleFrom(styles.get("header"));	//预设样式
		//创建Sheet
		HSSFSheet sheet = wb.createSheet("发票清单");

		List<Map<String, Object>> dataListBySql = new TccLogisticsComprehensive()
				//logOrderBid 物流订单号
				//logInvoiceNo 物流发票号
				//FbaNo FBA号
				.addLeftJoin("TCC_LogisticsChannelDetail B ON B.LogInvoiceNo = A.LogInvoiceNo")
				.addField("B.TransportationId AS transportationId")// 物流类型 0.快递|其他.物流
				.addField("B.NameLogsticsClearance AS nameLogsticsClearance")//清关方式

				.addField("CASE " +
						"WHEN B.TransportationId = 0 THEN '快递' " +
						" ELSE '物流' END transportationIdTxt")

				.addField("CASE " +
						"WHEN B.NameLogsticsClearance = "+TccFbaLogisticsMethodEnum.NameLogsticsClearance.FARMINGTAXES.value+" THEN '包税' " +
						" ELSE '自税' END nameLogsticsClearanceTxt")

				.addLeftJoin("TCC_TransportationType C ON C.Id = B.TransportationId")
				.addField("C.TransportationTypeCn AS transportationTypeCn")// 物流方式

				.addLeftJoin("TCC_FbaPlan D ON D.Bid = A.FbaPlanBid")
				.addField("D.Vgsbm AS vgsbm")// 公司名称
				.addField("D.VgsJc AS vgsJc")// 公司简称

				.addLeftJoin("TCC_LogisticsServiceProvider E ON E.ProviderBid = B.ProviderCode")

				.addField("E.Abbreviation AS abbreviation")// 物流服务商

				.addLeftJoin("TCC_FbaDeliverItem G ON G.Id = A.FbaDeliverItemId")
				.addLeftJoin("TCC_FbaBoxUpInfo F ON F.Id = G.FbaBoxUpInfoId")
				.addField("F.FbaTrackNo AS fbaTrackNo")// 货物追踪码



				.addLeftJoin("TCC_FbaBoxDetail H ON H.FbaBoxUpInfoId = F.Id")
				.addField("H.BoxNo AS boxNo")// 货箱编号
				.addField("H.Num AS fbaBoxDetailNum")// 发货数量
				.addField("H.PurchaseAmount AS purchaseAmount")//最终采购价 (单价)

				.addLeftJoin("TCC_FbaBoxUpItem I ON I.Id = H.BoxUpItemId")
				.addField("I.GoodsLink AS linkIn")// 商品链

				.addLeftJoin("TCC_FbaBox J ON J.Id = H.BoxId")
				.addField("J.BoxLong AS boxLong")// 长
				.addField("J.BoxWide AS boxWide")// 宽
				.addField("J.BoxHigh AS boxHigh")// 高
				.addField("J.BoxWeight AS boxWeight")// 实重
				.addField("(J.BoxLong * J.BoxWide * J.BoxHigh) / CAST(B.CoefficientWeight AS DECIMAL(10, 2)) AS boxWeightVol")// 抛重

				.addLeftJoin("TCC_LogisticsDetailChannelFee K ON K.LogInvoiceNo = A.LogInvoiceNo")
				.addField("K.ShipOrderWeight AS shipOrderWeight")// 计重（kg）===》 总重量 kg

				.addField("K.LogsticsChannelName  AS logsticsChannelName ")//物流渠道名称 => 物流名称


				.addLeftJoin("TCC_FbaPlanItem L ON L.Id = I.FbaPlanItemId")
				.addField("L.CodeGoodsHs AS codeGoodsHs")// HS Code 海关编码
				.addField("L.Img AS img")// 产品图片
				.addField("L.NameGoodsCn AS nameGoodsCn")// 商品品名（中文）
				.addField("L.NameMaterialCn AS nameMaterialCn")// 商品材质（中文）
				.addField("L.PriceIn AS priceIn")// 产品单个采购价 （￥）
				.addField("L.WeightPackage AS weightPackage")// 产品单个重量 (kg)
				.addField("L.IsSign AS isSign")// 透明标记
				.addField("L.Sku AS sku")//sku
				.addField("L.CommodityCode AS commodityCode")//商品编码


				.addLeftJoin("TP_ProductActive M ON M.Code = L.CommodityCode")
				//.addField("M.LinkIn AS linkIn")// 产品链接
				.addField("M.SpMcGg AS spMcGg")// 型号

				.addLeftJoin("TS_UserChange N ON N.Id = D.CreateChangeId")
				.addField("N.UserName AS planCreateUser")// 头程计划制单人

				.addLeftJoin("TB_BaseinfoSppm O ON O.Id = M.NameId")
				.addField("O.NameEn AS nameEn")// 产品品名 (英文）

				.addLeftJoin("TB_BaseinfoSpyt P ON P.Id = M.UsageId")
				.addField("P.UsageCn AS usageCn")// 产品用途 （中文）
				.addField("P.UsageEn AS usageEn")// 产品用途 （英文）

				.addLeftJoin("TB_BaseinfoDwmc Q ON Q.Id = M.NameUnitId")
				.addField("Q.NameUnitCn AS nameUnitCn")// 产品单位

				.addField("STUFF((SELECT ',' + R.MaterialNameEn FROM TP_ProductMaterial R WHERE R.Type = 3 AND R.ProductCode = M.Code ORDER BY R.MaterialNameCn FOR XML PATH('')), 1, 1, '') AS materialEn")// 产品材质 （英文）

				.addLeftJoin("TP_AmazonShopProduct S ON S.Id = L.AmazonShopProductId")
				.addField("S.Brand AS brand")// 品牌

				.addLeftJoin("TP_AmazonShop T ON T.Id = S.ShopId")
				.addField("T.VAT AS vat")//VAT
				.addField("T.EORI AS eori")//EORI
				.addField("T.Phone AS corporationPhone")// 运营公司法人联系电话

				.addField("T.DistrictOrCounty AS districtOrCountyByShop")
				.addField("T.Name AS nameByShop")
				.addField("T.AddressLine1 AS addressLine1ByShop")// 发货地址
				.addField("T.AddressLine2 AS addressLine2ByShop")
				.addField("T.City AS cityByShop")
				.addField("T.StateOrProvinceCode AS stateOrProvinceCodeByShop")
				.addField("T.CountryCode AS countryCodeByShop")
				.addField("T.PostalCode AS postalCodeByShop")



				.addLeftJoin("TP_AmazonAddress U ON U.DestinationFulfillmentCenterId = F.FbaWarehouse")
				.addField("U.Name AS amazonAddName")// 亚马逊仓库
				.addField("U.AddressLine1 AS amazonAddressLine")// 亚马逊仓库地址

				.addField("U.DistrictOrCounty AS districtOrCountyByAddress")
				.addField("U.Name AS nameByAddress")
				.addField("U.AddressLine1 AS addressLine1ByAddress")
				.addField("U.AddressLine2 AS addressLine2ByAddress")
				.addField("U.City AS cityByAddress")
				.addField("U.StateOrProvinceCode AS stateOrProvinceCodeByAddress")
				.addField("U.CountryCode AS countryCodeByAddress")
				.addField("U.PostalCode AS postalCodeByAddress")
				.addField("U.DestinationFulfillmentCenterId AS destinationFulfillmentCenterIdByAddress")

				.addLeftJoin("THR_OperateCompanyApply V ON V.Vgsbm = D.Vgsbm")
				//.addField("V.CorporationPhone AS corporationPhone")// 运营公司法人联系电话
				.addField("V.VGsMc AS vGsMc")//公司全称

				.where("A.LogInvoiceNo IN ("+logInvoiceNos.toString()+")")
				.setOrderby("A.LogInvoiceNo ")
				.queryMap();


		// *** 计算 ***
		// boxCount 箱数
		// totalAmount 合计采购价 （￥）
		// totalAmount1 合计采购价 （￡）
		// totalAmount2 合计采购价 （$）
		// volExponent 抛货指数 = 抛重-实重
		List<Map<String, Object>> dataList = new ArrayList<>();
		for(Map<String, Object> dataItem: dataListBySql){
			// 发货数量
			BigDecimal fbaBoxDetailNum = checkUtil.isNotNullByObject(dataItem.get("fbaBoxDetailNum")) ? new BigDecimal(dataItem.get("fbaBoxDetailNum").toString()):BigDecimal.ZERO;
			// 最终采购价 (单价)
			BigDecimal purchaseAmount = checkUtil.isNotNullByObject(dataItem.get("purchaseAmount")) ? new BigDecimal(dataItem.get("purchaseAmount").toString()):BigDecimal.ZERO;
			// 合计采购价 （￥） =  发货数量 * 最终采购价 (单价)
			BigDecimal totalAmount = fbaBoxDetailNum.multiply(purchaseAmount);

			// 1￥=0.1503＄=0.1189￡
			BigDecimal totalAmount1 = (totalAmount.multiply(new BigDecimal(0.1189))).setScale(2,BigDecimal.ROUND_HALF_UP);
			BigDecimal totalAmount2 = (totalAmount.multiply(new BigDecimal(0.1503))).setScale(2,BigDecimal.ROUND_HALF_UP);
			dataItem.put("totalAmount",totalAmount);
			dataItem.put("totalAmount1",totalAmount1);
			dataItem.put("totalAmount2",totalAmount2);

			// 抛重
			BigDecimal boxWeightVol = checkUtil.isNotNullByObject(dataItem.get("boxWeightVol")) ? new BigDecimal(dataItem.get("boxWeightVol").toString()):BigDecimal.ZERO;
			// 实重
			BigDecimal boxWeight = checkUtil.isNotNullByObject(dataItem.get("boxWeight")) ? new BigDecimal(dataItem.get("boxWeight").toString()):BigDecimal.ZERO;
			//抛货指数 = 抛重-实重
			BigDecimal volExponent = boxWeightVol.subtract(boxWeight);
			dataItem.put("volExponent",volExponent);

			//发票号
			String logInvoiceNo = dataItem.get("logInvoiceNo").toString();
			//根据发票号 过滤
			List<Map<String, Object>> dataListByLogInvoiceNo = dataListBySql.stream().filter(e->e.get("logInvoiceNo").toString().equals(logInvoiceNo)).collect(Collectors.toList());
			//根据货箱编号去重
			List<Map<String, Object>> groupsByList = ToolUtil.groupsByList(dataListByLogInvoiceNo,e->e.get("boxNo").toString());
			dataItem.put("boxCount",groupsByList.size());// boxCount 箱数

			dataList.add(dataItem);
		}


		List<YsCol> printColList = getPrintColInfo();
		// 创建表头行
		Row headerRow = sheet.createRow(0);
		for(int i=0;i<printColList.size();i++){
			// 创建表头单元格
			Cell headerCell = headerRow.createCell(i);
			headerCell.setCellValue(printColList.get(i).getName());
			headerCell.setCellStyle(styles.get("header"));
		}

		// 填充数据
		for (int i=0;i<dataList.size(); i++) {
			Map<String, Object> dataItem = dataList.get(i);
			Row dataRow = sheet.createRow(i + 1);
			for(int j = 0; j < printColList.size(); j++) {
				Cell dataCell = dataRow.createCell(j);
				String colCode = printColList.get(j).getCode();
				if(colCode.equals("addressLine1")){//发货地址
					ArrayList<String> arrayList = new ArrayList<String>();
					arrayList.add(dataItem.get("nameByShop")!=null?dataItem.get("nameByShop").toString():"");
					arrayList.add(dataItem.get("addressLine1ByShop")!=null?dataItem.get("addressLine1ByShop").toString():"");
					arrayList.add(dataItem.get("addressLine2ByShop")!=null?dataItem.get("addressLine2ByShop").toString():"");
					arrayList.add((dataItem.get("cityByShop")!=null?dataItem.get("cityByShop").toString():"") + ","
							+ (dataItem.get("stateOrProvinceCodeByShop")!=null?dataItem.get("stateOrProvinceCodeByShop").toString():"") + " "
							+ (dataItem.get("postalCodeByShop")!=null?dataItem.get("postalCodeByShop").toString():""));
					arrayList.add("CN");
//                    arrayList.add(printList2.getCountryCode());
					String content = String.join("\n", arrayList);

					dataCell.setCellValue(content);

				}else if(colCode.equals("amazonAddressLine")){//亚马逊仓库地址

					//com.dhecp.project.logstics.service.impl.FbaLogisticsOrderServicelmpl
					ArrayList<String> arrayList = new ArrayList<String>();
					arrayList.add(dataItem.get("nameByAddress")!=null?dataItem.get("nameByAddress").toString():"");
					arrayList.add(dataItem.get("addressLine1ByAddress")!=null?dataItem.get("addressLine1ByAddress").toString():"");
					arrayList.add(
							(dataItem.get("cityByAddress")!=null?dataItem.get("cityByAddress").toString():"")
							+ ","
							+ (dataItem.get("stateOrProvinceCodeByAddress")!=null?dataItem.get("stateOrProvinceCodeByAddress").toString():"")
							+ " "
							+ (dataItem.get("postalCodeByAddress")!=null?dataItem.get("postalCodeByAddress").toString():"")
					);
					arrayList.add(
							(dataItem.get("countryCodeByAddress")!=null?dataItem.get("countryCodeByAddress").toString():"")
							+ " ("
							+ (dataItem.get("destinationFulfillmentCenterIdByAddress")!=null?dataItem.get("destinationFulfillmentCenterIdByAddress").toString():"")
							+ ")"
					);
					String content = String.join("\n", arrayList);
					dataCell.setCellValue(content);

				}else{
					dataCell.setCellValue(dataItem.get(colCode)!=null && !"img".equals(colCode) ?dataItem.get(colCode).toString():"");
				}

				dataCell.setCellStyle(styles.get("data"));
			}

			if(dataItem.get("img")!=null){
				addPhotograph(sheet , wb, dataItem.get("img").toString(),i);
			}

		}


		// 导出Excel文件
		String filePath = "发票清单_"+new Date().getTime()+".xlsx";
		String downloadPath = MyConfig.getProfile() + "/" + filePath;
		File file = new File(downloadPath);
		FileOutputStream fos = new FileOutputStream(file);
		wb.write(fos);
		fos.close();
		UploadService.UploadDto dto = commonApiService.uploadLocalToServer(downloadPath);
		//返回文件路径
		return R.ok(dto.getUrl());

	}



	/**
	 * 添加图片
	 * @return
	 */
	private void  addPhotograph(HSSFSheet sheet ,HSSFWorkbook wb, String urls, Integer i) throws Exception{
		//给标题插入图片
		ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
//        URL url = new URL("http://cdn.mini-ease.com/profile/images/20230110/fa57b92248dbf21b479e7efd2cd25298.jpg");
		URL url = new URL(urls);
		BufferedImage bi = ImageIO.read(url);
		if (bi != null) {

			//获取长宽
//        Integer width = bi.getWidth();
//        Integer height = bi.getHeight();
			// 将图片写入流中
			ImageIO.write(bi, "png", byteArrayOut);
			// 利用HSSFPatriarch将图片写入EXCEL
			HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
			/**
			 * 该构造函数有8个参数
			 * int dx1, int dy1, int dx2, int dy2,
			 * short col1, int row1, short col2, int row2
			 * excel中的cellNum和rowNum的index都是从0开始的
			 */
			//图片一导出到单元格中
			HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0,
					(short) 31, i+1, (short) 32, i + 2);
			// 插入图片
			patriarch.createPicture(anchor, wb.addPicture(byteArrayOut
					.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG));
		}
	}



	//获取发票导出 表头信息
	public List<YsCol> getPrintColInfo(){
		List<YsCol> colList = new ArrayList<>();

		colList.add( new YsCol().setCode("logOrderBid").setName("物流订单号"));
		colList.add( new YsCol().setCode("logInvoiceNo").setName("物流发票号"));
		colList.add( new YsCol().setCode("transportationIdTxt").setName("物流类型"));
		colList.add( new YsCol().setCode("transportationTypeCn").setName("物流方式"));
		colList.add( new YsCol().setCode("nameLogsticsClearanceTxt").setName("清关方式"));
		colList.add( new YsCol().setCode("vgsbm").setName("公司名称"));
		colList.add( new YsCol().setCode("vgsJc").setName("公司简称"));
		colList.add( new YsCol().setCode("vGsMc").setName("公司名称全称"));
		colList.add( new YsCol().setCode("corporationPhone").setName("电话"));
		colList.add( new YsCol().setCode("addressLine1").setName("发货地址"));
		colList.add( new YsCol().setCode("amazonAddressLine").setName("亚马逊仓库地址"));
		colList.add( new YsCol().setCode("vat").setName("VAT"));
		colList.add( new YsCol().setCode("eori").setName("EORI"));
		colList.add( new YsCol().setCode("amazonAddName").setName("亚马逊仓库"));
		colList.add( new YsCol().setCode("fbaNo").setName("FBA号"));
		colList.add( new YsCol().setCode("fbaTrackNo").setName("货物追踪码"));
		colList.add( new YsCol().setCode("boxCount").setName("箱数"));
		colList.add( new YsCol().setCode("boxNo").setName("货箱编号"));
		colList.add( new YsCol().setCode("boxLong").setName("长"));
		colList.add( new YsCol().setCode("boxWide").setName("宽"));
		colList.add( new YsCol().setCode("boxHigh").setName("高"));
		colList.add( new YsCol().setCode("boxWeightVol").setName("抛重"));
		colList.add( new YsCol().setCode("boxWeight").setName("实重"));
		colList.add( new YsCol().setCode("volExponent").setName("抛货指数"));
		colList.add( new YsCol().setCode("totalAmount").setName("合计采购价 （￥）"));
		colList.add( new YsCol().setCode("totalAmount1").setName("合计采购价 （￡）"));
		colList.add( new YsCol().setCode("totalAmount2").setName("合计采购价 （$）"));
		colList.add( new YsCol().setCode("shipOrderWeight").setName("总重量 kg"));
		colList.add( new YsCol().setCode("commodityCode").setName("商品编码"));
		colList.add( new YsCol().setCode("brand").setName("品牌"));
		colList.add( new YsCol().setCode("spMcGg").setName("型号"));
		colList.add( new YsCol().setCode("img").setName("产品图片"));
		colList.add( new YsCol().setCode("nameGoodsCn").setName("产品品名 （中文）"));
		colList.add( new YsCol().setCode("nameEn").setName("产品品名 (英文）"));
		colList.add( new YsCol().setCode("codeGoodsHs").setName("HS Code 海关编码"));
		colList.add( new YsCol().setCode("nameMaterialCn").setName("产品材质 （中文）"));
		colList.add( new YsCol().setCode("materialEn").setName("产品材质 （英文）"));
		colList.add( new YsCol().setCode("usageCn").setName("产品用途 （中文）"));
		colList.add( new YsCol().setCode("usageEn").setName("产品用途 （英文）"));
		colList.add( new YsCol().setCode("weightPackage").setName("产品单个重量 (kg)"));
		colList.add( new YsCol().setCode("priceIn").setName("产品单个采购价 （￥）"));
		colList.add( new YsCol().setCode("nameUnitCn").setName("产品单位"));
		colList.add( new YsCol().setCode("linkIn").setName("产品链接"));
		colList.add( new YsCol().setCode("fbaBoxDetailNum").setName("发货数量"));
		colList.add( new YsCol().setCode("planCreateUser").setName("头程计划制单人"));
		colList.add( new YsCol().setCode("isSign").setName("透明标记"));
		colList.add( new YsCol().setCode("logsticsChannelName").setName("物流名称"));
		colList.add( new YsCol().setCode("abbreviation").setName("物流服务商"));

		return colList;
	}





	/**
	 * 创建表格样式
	 * @param wb 工作薄对象
	 * @return 样式列表
	 */
	public Map<String, CellStyle> createStyles(HSSFWorkbook wb){
		// 写入各条记录,每条记录对应excel表中的一行
		Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
		CellStyle style = wb.createCellStyle();
		style.setAlignment(HorizontalAlignment.LEFT);	//设置单元格的水平对齐类型（居左）
		style.setVerticalAlignment(VerticalAlignment.CENTER);	//设置单元格的垂直对齐类型（居中）
		style.setBorderRight(BorderStyle.THIN);	//设置单元格右边框的边框类型
		style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());	//设置右边边框的颜色
		style.setBorderLeft(BorderStyle.THIN);	//设置单元格左边框的边框类型
		style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());	//设置左边框的颜色
		style.setBorderTop(BorderStyle.THIN);	//设置单元格上边框使用的边框类型
		style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());	//设置上边框的颜色
		style.setBorderBottom(BorderStyle.THIN);	//设置单元格下边框使用的边框类型
		style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());	//设置下边框的颜色
		Font dataFont = wb.createFont();
		dataFont.setFontName("仿宋");	//设置字体的名称(例如:仿宋)
		dataFont.setFontHeightInPoints((short) 12);	//设置字体高度
		style.setFont(dataFont);
		styles.put("data", style);


		style = wb.createCellStyle();
		style.cloneStyleFrom(styles.get("data"));
		style.setAlignment(HorizontalAlignment.CENTER);	//设置单元格的水平对齐类型（居中）
		style.setVerticalAlignment(VerticalAlignment.CENTER);	//设置单元格的垂直对齐类型（居中）
		style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());	//
		style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
		Font headerFont = wb.createFont();
		dataFont.setFontName("仿宋");	//设置字体的名称(例如:仿宋)
		headerFont.setFontHeightInPoints((short) 16);	//设置字体高度
		headerFont.setBold(true);
		headerFont.setColor(IndexedColors.WHITE.getIndex());
		style.setFont(headerFont);
		styles.put("header", style);


		return styles;
	}



	/**
	 * 物流订单取消（api）
	 * @param choooseList 选择的数据
	 */
	@Override
	public R apiCancel(List<Map<String, Object>> choooseList)throws Exception{

		int doCount = 0;

		//去除订单号为空的
		List<Map<String, Object>> spOrderBidNotNullList = choooseList.stream()
				.filter(e->checkUtil.isNotNullByObject(e.get("spOrderBid"))
						&& Integer.parseInt(e.get("apiPlaceOrderStatus").toString())!=TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.CANCEL.value
						&& Integer.parseInt(e.get("apiPlaceOrderStatus").toString())!=TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.EMPTY.value
				)
				.collect(Collectors.toList());

		//根据订单号去重
		List<Map<String, Object>> spOrderBidList = ToolUtil.groupsByList(spOrderBidNotNullList, e->e.get("spOrderBid").toString());

		StringBuilder resMsg = new StringBuilder();
		for (int i = 0; i < spOrderBidList.size(); i++) {
			Map<String, Object> info = spOrderBidList.get(i);
			String spOrderBid = info.get("spOrderBid").toString();
			//处理
			R res = tccLogisticsApiService.cancelorder(spOrderBid);
			if(res.getCode()==0){
				//修改API状态
				storageMapper.apiCancelStatusByLogisticsComprehensive(spOrderBid,TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.CANCEL.value);
				doCount ++;
			}else{
				resMsg.append((info.get("logInvoiceNo")!=null?"发票号："+info.get("logInvoiceNo"):"")+"；")
						.append(res.getMsg())
						.append("</br>");
			}
		}
		StringBuilder resMsgTotal = new StringBuilder().append("成功物流订单取消（api）").append(doCount).append("条数据</br>").append(resMsg);
		return R.ok(resMsgTotal.toString());

	}


	/**
	 * 标签获取打印（api）
	 * @param choooseList 选择的数据
	 */
	@Override
	public R apiPrintTag(List<Map<String, Object>> choooseList)throws Exception{
		//去除订单号为空的
		List<Map<String, Object>> spOrderBidNotNullList = choooseList.stream().filter(e->checkUtil.isNotNullByObject(e.get("spOrderBid"))).collect(Collectors.toList());

		//根据订单号去重
		List<Map<String, Object>> spOrderBidListByGroup = ToolUtil.groupsByList(spOrderBidNotNullList, e->e.get("spOrderBid").toString());

		List<String> spOrderBidList = new ArrayList<>();
		for(Map<String, Object> item:spOrderBidListByGroup){
			spOrderBidList.add(item.get("spOrderBid").toString());
		}

		R r = tccLogisticsApiService.print(spOrderBidList);

		List<String> pdfUrl = new ArrayList<>();
		if (r.getCode() != null){
			if (r.getCode().equals(0)){
				//处理费用
				JSONObject getData = JSONObject.parseObject(r.get("data").toString());
				if (spOrderBidList.size() > 1){
					JSONArray dataList = JSONArray.parseArray(getData.get("data").toString());
					if(dataList!=null && dataList.size()>0){
						for(int i=0;i<dataList.size();i++){
							JSONObject jsonObjectData = (JSONObject)dataList.get(i);
							//设置对应的fba信息pdf
//							String spOrderBids = storageMapper.getFbaList(jsonObjectData.get("orderno").toString());
//							String urlFba = pdfService.getUrlFba(spOrderBids,jsonObjectData.get("packno").toString());
//							pdfUrl.add(urlFba);
							String url = jsonObjectData.get("nburl").toString();
							if (url.contains("\\")){
								url = jsonObjectData.get("nburl").toString().replace("\\","//");
							}
							R getUrlr = getUrl(url,jsonObjectData);
							if (getUrlr.getCode() == 0){
								pdfUrl.add(getUrlr.get("msg").toString());
							}else {
								return R.error(getUrlr.getMsg());
							}
						}
					}
				}else {
					JSONObject dataList = JSONObject.parseObject(getData.get("data").toString());
					if(dataList!=null){
//						设置对应的fba信息pdf
//						String spOrderBids = storageMapper.getFbaList(dataList.get("orderno").toString());
//						String urlFba = pdfService.getUrlFba(spOrderBids,dataList.get("packno").toString());
//						pdfUrl.add(urlFba);
						String url = dataList.get("nburl").toString();
						if (url.contains("\\")){
							url = dataList.get("nburl").toString().replace("\\","//");
						}
						R getUrlr = getUrl(url,dataList);
						if (getUrlr.getCode() == 0){
							pdfUrl.add(getUrlr.get("msg").toString());
						}else {
							return R.error(getUrlr.getMsg());
						}
					}
				}

			}
		}else {
			return R.error("打印失败!");
		}
//		pdfUrl.add("http://8.134.39.115:8000/file//20250317//8441185114MDM.pdf");
//		pdfUrl.add("http://8.134.39.115:8000/file//20250317//1298787026MDM.pdf");
//		pdfUrl.add("https://file.mini-ease.com/upload/nomodule/202405/10/114137916.pdf");

		return R.ok(pdfUrl);
	}

	private R getUrl(String url,JSONObject dataList){
		try {
			URL downloadURL = new URL(url);
			HttpURLConnection conn = (HttpURLConnection) downloadURL.openConnection();
			// 设置超时间为3秒
			conn.setConnectTimeout(3 * 1000);
			// 防止屏蔽程序抓取而返回403错误
			conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

			// 得到输入流
			InputStream inputStream = conn.getInputStream();

			byte[] buffer = new byte[1024];
			int len = 0;
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			while ((len = inputStream.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
			}
			bos.close();
			// 获取字节数组
			byte[] getData = bos.toByteArray();
			String dir = MyConfig.getProfile();
			// 文件保存位置
			File saveDir = new File(dir);
			if (!saveDir.exists()) {
				saveDir.mkdir();
			}
			String pdfFileName = "/pdf/" + dataList.get("orderno") + ".pdf";
			File file = new File(saveDir + pdfFileName);
			String data = MyConfig.getUrlDomain() + "/upload/pdf/" + dataList.get("orderno") + ".pdf";
			FileOutputStream fos = new FileOutputStream(file);
			fos.write(getData);
			if (fos != null) {
				fos.close();
			}
			if (inputStream != null) {
				inputStream.close();
			}
			return R.ok(data);
		} catch (Exception e) {
			logger.error("下载箱标失败:" + e.getMessage());
			return R.error(e.getMessage());
		}
	}


	@Override
	public List<Map<String, Object>> getInfoByCreateOrder(TccLogisticsComprehensive tccLogisticsComprehensive)throws Exception{
		List<Map<String, Object>> dataListBySql = new TccLogisticsComprehensive()
				//logOrderBid 物流订单号
				//logInvoiceNo 物流发票号
				//FbaNo FBA号
				.addLeftJoin("TCC_LogisticsChannelDetail B ON B.LogInvoiceNo = A.LogInvoiceNo AND B.Bid = A.LogOrderBid")
				.addField("B.TransportationId AS transportationId")// 物流类型 0.快递|其他.物流
				.addField("B.NameLogsticsClearance AS nameLogsticsClearance")//清关方式（0包税、1自税）



				.addLeftJoin("TCC_TransportationType C ON C.Id = B.TransportationId")
				.addField("C.TransportationTypeCn AS transportationTypeCn")// 物流方式

				.addLeftJoin("TCC_FbaPlan D ON D.Bid = A.FbaPlanBid")
				.addField("D.Vgsbm AS vgsbm")// 公司名称
				.addField("D.VgsJc AS vgsJc")// 公司简称

				.addLeftJoin("TCC_LogisticsServiceProvider E ON E.ProviderBid = B.ProviderCode")

				.addField("E.Abbreviation AS abbreviation")// 物流服务商

				.addLeftJoin("TCC_FbaDeliverItem G ON G.Id = A.FbaDeliverItemId")
				.addLeftJoin("TCC_FbaBoxUpInfo F ON F.Id = G.FbaBoxUpInfoId")
				.addField("F.FbaTrackNo AS fbaTrackNo")// 货物追踪码
				.addField("F.FbaWarehouse AS fbaWarehouse")// FBA仓库
				.addField("F.FbaTrackNo AS fbaTrackNo")// FBA追踪编码

				.addLeftJoin("TCC_FbaBoxDetail H ON H.FbaBoxUpInfoId = F.Id")
				.addField("H.BoxNo AS boxNo")// 货箱编号
				.addField("H.Num AS fbaBoxDetailNum")// 发货数量
				.addField("H.PurchaseAmount AS purchaseAmount")//最终采购价 (单价)

				.addLeftJoin("TCC_FbaBoxUpItem I ON I.Id = H.BoxUpItemId")
				.addField("I.GoodsLink AS linkIn")// 商品链接

				.addLeftJoin("TCC_FbaBox J ON J.Id = H.BoxId")
				.addField("J.BoxLong AS boxLong")// 长
				.addField("J.BoxWide AS boxWide")// 宽
				.addField("J.BoxHigh AS boxHigh")// 高
				.addField("J.BoxWeight AS boxWeight")// 实重
//                .addField("(J.BoxLong * J.BoxWide * J.BoxHigh) / CAST(B.CoefficientWeight AS DECIMAL(10, 2)) AS boxWeightVol")// 抛重
//
//                .addLeftJoin("TCC_LogisticsDetailChannelFee K ON K.LogInvoiceNo = A.LogInvoiceNo")
//                .addField("K.ShipOrderWeight AS shipOrderWeight")// 计重（kg）===》 总重量 kg
//
//                .addField("K.LogsticsChannelName  AS logsticsChannelName ")//物流渠道名称 => 物流名称


				.addLeftJoin("TCC_FbaPlanItem L ON L.Id = I.FbaPlanItemId")
				.addField("L.CodeGoodsHs AS codeGoodsHs")// HS Code 海关编码
				.addField("L.Img AS img")// 产品图片
				.addField("L.NameGoodsCn AS nameGoodsCn")// 商品品名（中文）
				.addField("L.NameMaterialCn AS nameMaterialCn")// 商品材质（中文）
				.addField("L.PriceIn AS priceIn")// 产品单个采购价 （￥）
				.addField("L.WeightPackage AS weightPackage")// 产品单个重量 (kg)
				.addField("L.IsSign AS isSign")// 透明标记
				.addField("L.Sku AS sku")//sku


				.addLeftJoin("TP_ProductActive M ON M.Code = L.CommodityCode")
				//.addField("M.LinkIn AS linkIn")// 产品链接
				.addField("M.SpMcGg AS spMcGg")// 型号

//				.addLeftJoin("(SELECT MAX(Z1.LinkIn) AS LinkIn,Z1.Pcode FROM TP_ProductBasisComponent Z1  GROUP BY Z1.Pcode) Z ON Z.Pcode = M.Code")
//				.addField("Z.LinkIn AS linkIn")// 产品链接

//                .addLeftJoin("TS_UserChange N ON N.Id = D.CreateChangeId")
//                .addField("N.UserName AS planCreateUser")// 头程计划制单人

				.addLeftJoin("TB_BaseinfoSppm O ON O.Id = M.NameId")
				.addField("O.NameEn AS nameEn")// 产品品名 (英文）

				.addLeftJoin("TB_BaseinfoSpyt P ON P.Id = M.UsageId")
				.addField("P.UsageCn AS usageCn")// 产品用途 （中文）
				.addField("P.UsageEn AS usageEn")// 产品用途 （英文）

//                .addLeftJoin("TB_BaseinfoDwmc Q ON Q.Id = M.NameUnitId")
//                .addField("Q.NameUnitCn AS nameUnitCn")// 产品单位

				.addField("STUFF((SELECT ',' + R.MaterialNameEn FROM TP_ProductMaterial R WHERE R.Type = 3 AND R.ProductCode = M.Code ORDER BY R.MaterialNameCn FOR XML PATH('')), 1, 1, '') AS materialEn")// 产品材质 （英文）

				.addLeftJoin("TP_AmazonShopProduct S ON S.Id = L.AmazonShopProductId")
				.addField("S.Brand AS brand")// 品牌

				.addLeftJoin("TP_AmazonShop T ON T.Id = S.ShopId")
				.addField("T.VAT AS vat")//VAT
				.addField("T.EORI AS eori")//EORI
				.addField("T.AddressLine1 AS addressLine1")// 发货地址
				.addField("T.AddressLine2 AS addressLine2")// 发货地址
				.addField("T.Vgsjc AS vgsjc")//所属公司名称
				.addField("T.Phone AS phone")//联系电话
				.addField("T.PostalCode AS postalCode")//邮编
				.addField("T.DistrictOrCounty AS districtOrCounty")//
				.addField("T.City AS city")//城市
				.addField("T.Name AS addrName")//仓库名称


//
//                .addLeftJoin("TP_AmazonAddress U ON U.DestinationFulfillmentCenterId = F.FbaWarehouseAddr")
//                .addField("U.Name AS amazonAddName")// 亚马逊仓库
//                .addField("U.AddressLine1 AS amazonAddressLine")// 亚马逊仓库地址

				.addLeftJoin("THR_OperateCompanyApply V ON V.Vgsbm = D.Vgsbm")
				.addField("V.CorporationPhone AS corporationPhone")// 运营公司法人联系电话

				.addLeftJoin("TS_UserInfo Y ON Y.UserId = V.Cuser")
				.addField("Y.UserName AS companyUser")//


				.addLeftJoin("TB_Country W ON W.Code = B.Country")
				.addLeftJoin("TP_AmazonShopExchangeRate X ON X.Id = W.AmazonShopExchangeRateId")

				.addField("X.Code AS currencyCode")//货币代码

				.setLogInvoiceNo(tccLogisticsComprehensive.getLogInvoiceNo())
				.setOrderby("A.LogInvoiceNo ")
				.queryMap();
		return dataListBySql;
	}







	/**
	 * api下单
	 * @param logInvoiceNo 发票信息
	 */
	@Override
	public R apiPlaceOrder(String logInvoiceNo)throws Exception{
		TccLogisticsComprehensive tccLogisticsComprehensive = new TccLogisticsComprehensive().setLogInvoiceNo(logInvoiceNo).queryFirst();

		if(tccLogisticsComprehensive.getLogInvoiceWeight()==null || tccLogisticsComprehensive.getLogInvoiceWeight().compareTo(BigDecimal.ZERO)==0){
			return R.error("还未进行按单收费核算，无法进行api下单；");
		}

		//获取可以确认下单的状态
		List<TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus> getApiConfirmStatusList = TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getApiConfirmStatus();

		//验证API下单状态 ，只有：空，成功（匹配） 才可过
		if(!TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.checkStatus(getApiConfirmStatusList,tccLogisticsComprehensive.getApiPlaceOrderStatus())){
			return R.error("API下单状态只有："+TccLogisticsComprehensiveEnum.ApiPlaceOrderStatus.getNameStrByList(getApiConfirmStatusList)+"，才可进行API下单！");
		}

		//api操作
		return tccLogisticsApiService.createorder(tccLogisticsComprehensive);
	}


	/**
	 * 获取目的地
	 * @param valueot 国家(US)
	 * @return
	 */
	@Override
	public String getDest(String valueot){
		String code = null;
//		String[] list = valuenm.split("/");
//		String fbaWarehouse =  valuenm;
//		if (list.length > 1){
//			//LBA8/IMN1
//			fbaWarehouse = list[0];
//		}
		TbCountry tbCountry = new TbCountry().setCode(valueot).setStatus(1).queryFirst();
		if(tbCountry==null || tbCountry.getId()==null ){
			throw new IllegalArgumentException("国家："+valueot+"未维护！");
		}

		TccDest tccDest = new TccDest().setVtpye(1).setValueot(valueot).setValuenm(tbCountry.getName()).queryFirst();
		if(tccDest==null || tccDest.getId()==null ){
			throw new IllegalArgumentException("未找到valueot="+valueot+"，Valuenm="+tbCountry.getName()+"的目的地信息！");
		}else{
			code = tccDest.getValuecode();
		}

		return code;
	}

	/**
	 * C88文件下载（api）
	 * @param choooseList 选择的数据
	 */
	@Override
	public R apiGetC88(List<Map<String, Object>> choooseList)throws Exception{
		//去除订单号为空的
		List<Map<String, Object>> spOrderBidNotNullList = choooseList.stream().filter(e->checkUtil.isNotNullByObject(e.get("spOrderBid"))).collect(Collectors.toList());

		//根据订单号去重
		List<Map<String, Object>> spOrderBidListByGroup = ToolUtil.groupsByList(spOrderBidNotNullList, e->e.get("spOrderBid").toString());

		List<String> spOrderBidList = new ArrayList<>();
		for(Map<String, Object> item:spOrderBidListByGroup){
			spOrderBidList.add(item.get("spOrderBid").toString());
		}



		R r = tccLogisticsApiService.getfile(spOrderBidList);
		if (r.getCode() != null){
			if (r.getCode().equals(0)){
				// 文件上传到自己的服务器
				JSONObject getData = JSONObject.parseObject(r.get("data").toString());
				JSONArray dataList = JSONArray.parseArray(getData.get("data").toString());
				if(dataList!=null && dataList.size()>0){
					for(int i=0;i<dataList.size();i++){
						JSONObject jsonObjectData = (JSONObject)dataList.get(i);

						//物流商订单号
						String orderno = jsonObjectData.get("orderno").toString();
						//文件地址
						String url = jsonObjectData.get("url").toString();
						//系统文件地址
						R res = FileUtilYs.uploadFileByUrl(url);
						if (res.getCode().equals(0)){
							List<Map<String, Object>> spOrderBidListNew = spOrderBidNotNullList.stream().filter(e->e.get("spOrderBid").equals(orderno)).collect(Collectors.toList());

							if (spOrderBidListNew.size() != 0){
								List<TccLogisticsSadFile> tccLogisticsSadFileList = new TccLogisticsSadFile().setLogInvoiceNo(spOrderBidListNew.get(0).get("logInvoiceNo").toString()).queryList();
								for (TccLogisticsSadFile tccLogisticsSadFile : tccLogisticsSadFileList){
									TbFileInfo tbFileInfo = TbFileInfo.tbFileInfo(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value,tccLogisticsSadFile.getId(), "annexFile",
											orderno+",C88文件","pdf","pdf",0L,res.get("data").toString(),
											840L,1);
									tbFileInfoMapper.insert(tbFileInfo);

									tccLogisticsSadFile.setAnnexFile("1个附件");
									tccLogisticsSadFileMapper.update(tccLogisticsSadFile);
								}
							}
						}
					}
				}
			}
		}else {
			return R.error("C88文件获取失败!");
		}
		return R.ok(r);
	}





	/**
	 * 获取快驿通C88文件（api）- 定时器
	 */
	@Override
	public void apiGetC88ByTimerKyt()throws Exception{
		//C88 自税、为空 的才需要获取
		List<TccLogisticsComprehensive> logisticsList = new TccLogisticsComprehensive()
				.addLeftJoin("TCC_LogisticsChannelDetail B ON B.LogInvoiceNo = A.LogInvoiceNo")
				.addLeftJoin("TCC_LogisticsSadFile C ON C.LogisticsComprehensiveId = A.Id")
				//未上传C88文件的
				.where("( SELECT COUNT ( 1 ) AS num FROM TB_FileInfo D WHERE D.SourceId = C.Id AND D.SourceCode = 'annexFile' AND  D.SourceType = "+TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value+") = 0 ")
				.where("A.SpOrderBid IS NOT NULL AND B.NameLogsticsClearance = " + TccFbaLogisticsMethodEnum.NameLogsticsClearance.SELFTAX.value)
				.queryList();

		//根据订单号去重
		Map<String, List<TccLogisticsComprehensive>> groupsByStr = logisticsList.stream().collect(Collectors.groupingBy(e->e.getSpOrderBid()));
		List<TccLogisticsComprehensive> groupBySpOrderBidList = new ArrayList<>();
		//遍历，填入去重的信息
		groupsByStr.forEach((k, v) -> groupBySpOrderBidList.add(v.get(0)));

		//一次最多传20个单号
		int oneTimeNum = 20;

		//分页获取
		for(int pageNo=0;pageNo<groupBySpOrderBidList.size()+oneTimeNum;pageNo=pageNo+oneTimeNum){
			//分页
			List<TccLogisticsComprehensive> pageList = groupBySpOrderBidList.stream().skip(pageNo).limit(oneTimeNum).collect(Collectors.toList());

			List<String> spOrderBidList = new ArrayList<>();
			for(TccLogisticsComprehensive tccLogisticsComprehensive:pageList){
				spOrderBidList.add(tccLogisticsComprehensive.getSpOrderBid());
			}
			R r = tccLogisticsApiService.getfile(spOrderBidList);
			if (r.getCode() != null){
				if (r.getCode().equals(0)){
					// 文件上传到自己的服务器
					JSONObject getData = JSONObject.parseObject(r.get("data").toString());
					JSONArray dataList = JSONArray.parseArray(getData.get("data").toString());
					if(dataList!=null && dataList.size()>0){
						for(int i=0;i<dataList.size();i++){
							JSONObject jsonObjectData = (JSONObject)dataList.get(i);

							//物流商订单号
							String orderno = jsonObjectData.get("orderno").toString();
							//文件地址
							String url = jsonObjectData.get("url").toString();
							//系统文件地址
							R res = FileUtilYs.uploadFileByUrl(url);
							if (res.getCode().equals(0)){
								List<TccLogisticsComprehensive> pageListNew = pageList.stream().filter(e->e.getSpOrderBid().equals(orderno)).collect(Collectors.toList());

								if (pageListNew.size() != 0){
									List<TccLogisticsSadFile> tccLogisticsSadFileList = new TccLogisticsSadFile().setLogInvoiceNo(pageListNew.get(0).getLogInvoiceNo()).queryList();
									for (TccLogisticsSadFile tccLogisticsSadFile : tccLogisticsSadFileList){
										TbFileInfo tbFileInfo = TbFileInfo.tbFileInfo(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value,tccLogisticsSadFile.getId(), "annexFile",
												orderno+",C88文件","pdf","pdf",0L,res.get("data").toString(),
												840L,1);
										tbFileInfoMapper.insert(tbFileInfo);
										int countFile = new TbFileInfo()
												.setSourceId(tccLogisticsSadFile.getId())
												.setSourceType(TbFileInfoEnum.SourceType.TCC_LogisticsSadFile_AnnexFile.value)
												.setSourceCode("annexFile")
												.count();

										tccLogisticsSadFile.setAnnexFile(countFile+"个附件");
										tccLogisticsSadFileMapper.update(tccLogisticsSadFile);
									}
								}
							}
						}
					}
				}
			}else {
				logger.error("C88文件获取失败："+r);
			}
		}

	}


	/**
	 * 获取快驿通追踪编号（api）- 定时器
	 */
	@Override
	public void apiGetTrackNoByTimerKyt()throws Exception{
		List<TccLogisticsComprehensive> logisticsList = new TccLogisticsComprehensive()
				.where("A.SpOrderBid IS NOT NULL AND (A.TrackingCode IS NULL OR A.TrackingCode = '') ")
				.queryList();

		//根据订单号去重
		Map<String, List<TccLogisticsComprehensive>> groupsByStr = logisticsList.stream().collect(Collectors.groupingBy(e->e.getSpOrderBid()));
		List<TccLogisticsComprehensive> groupBySpOrderBidList = new ArrayList<>();
		//遍历，填入去重的信息
		groupsByStr.forEach((k, v) -> groupBySpOrderBidList.add(v.get(0)));

		for(TccLogisticsComprehensive tccLogisticsComprehensive:groupBySpOrderBidList){
			StringBuffer trackingCode = new StringBuffer();
			//api获取订单详情
			R apiRes = tccLogisticsApiService.getorder(tccLogisticsComprehensive.getLogInvoiceNo());
			//成功
			if(apiRes.getCode().equals(R.Code.SUCCESS.value)){

				JSONObject getData = JSONObject.parseObject(apiRes.get("data").toString());
				if(getData.get("data")!=null){
					JSONArray dataList = JSONArray.parseArray(getData.get("data").toString());
					JSONObject dataOne = dataList.getJSONObject(0);
					if(dataOne.get("details")!=null){
						JSONArray detailsArr = JSONArray.parseArray(dataOne.get("details").toString());
						for(int i=0;i<detailsArr.size();i++){
							JSONObject detailItem = detailsArr.getJSONObject(i);
							//箱子编号不为空
							if(checkUtil.isNotNullByObject(detailItem.get("cartonno"))){
								String cartonno = detailItem.get("cartonno").toString();//箱子编码

								//子转单号不为空
								if(checkUtil.isNotNullByObject(detailItem.get("transferno"))){
									String transferno = detailItem.get("transferno").toString();//追踪编号
									//修改发货单箱子对应的追踪编码
									storageMapper.updateTransfernoByBoxNo(transferno,cartonno);
									//拼接追踪编码
									if(trackingCode.length()>0){
										trackingCode.append(",");
									}
									trackingCode.append(transferno);
								}else{
									//子转单号为空，但主转单号不为空
									if(dataOne.get("zycode")!=null && !"".equals(dataOne.get("zycode"))){
										String codeNo = String.format("%0"+2+"d", (i+1));//格式：XXXX01、XXXX02...
										String transferno = dataOne.get("zycode").toString()+codeNo;
										//修改发货单箱子对应的追踪编码
										storageMapper.updateTransfernoByBoxNo(transferno,cartonno);
										//拼接追踪编码
										if(trackingCode.length()>0){
											trackingCode.append(",");
										}
										trackingCode.append(transferno);
									}
								}

							}


						}
					}
				}
			}

			if(trackingCode.length()>0){
				//修改物流订单的追踪编码
				storageMapper.updateTrackingCodeByLogInvoiceNo(trackingCode.toString(),tccLogisticsComprehensive.getLogInvoiceNo());
			}
		}
	}




	/**
	 * 物流轨迹查询
	 */
	@Override
	public R trackingSearch(String logInvoiceNo)throws Exception{
		TccLogisticsComprehensive tccLogisticsComprehensive = new TccLogisticsComprehensive().setLogInvoiceNo(logInvoiceNo).queryFirst();
		List<String> spOrderBidList = new ArrayList<>();
		spOrderBidList.add(tccLogisticsComprehensive.getSpOrderBid());

		//API获取物流轨迹
		R apiRes = tccLogisticsApiService.tracking(spOrderBidList);
		//成功
		if(apiRes.getCode().equals(R.Code.SUCCESS.value)){
			JSONObject getData = JSONObject.parseObject(apiRes.get("data").toString());
			if(getData.get("data")!=null){
				//获取接口返回参数
				JSONObject getDataByApi = getData.getJSONObject("data");
				if(getDataByApi.get("details")!=null){

					//获取api返回数据
					JSONArray detailList = JSONArray.parseArray(getDataByApi.get("details").toString());
					if(detailList!=null && detailList.size()>0){
						//存放返回集合
						List<Map<String,Object>> resList = new ArrayList<>();
						for(int i=0;i<detailList.size();i++){
							Map<String,Object> resMsg = new HashMap<>();
							JSONObject detailItem = detailList.getJSONObject(i);
							resMsg.put("acceptTime",detailItem.get("zztm"));
							resMsg.put("remark",detailItem.get("guiji"));
							resList.add(resMsg);
						}
						//按照时间顺序排序
						resList = resList.stream().sorted(Comparator.comparing(e->e.get("acceptTime").toString())).collect(Collectors.toList());
						return R.ok("获取成功",resList);
					}
				}
			}
		}else {
			return apiRes;
		}

		return R.ok("暂无物流轨迹");
	}



	/**
	 * 按单收费核算
	 */
	@Override
	public R countCost(String logisticsMarkingBid)throws Exception{

		//验证：
		List<TccLogisticsComprehensive> logisticsList = new TccLogisticsComprehensive()
				.setLogisticsMarkingBid(logisticsMarkingBid)
				.setStatus(TccLogisticsComprehensiveEnum.Status.GENERATED.value)
				.queryList();

		if(logisticsList!=null && logisticsList.size()>0){
			for(TccLogisticsComprehensive item:logisticsList){
				if(item.getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value)){
					return R.error("计算方式为：按物流发票，无需按单收费核算");
				}
				if(item.getLogInvoiceWeight()!=null && item.getLogInvoiceWeight().compareTo(BigDecimal.ZERO)!=0){
					return R.error("已经核算过，无需再次核算（可点击\"按单收费核算取消\"后再进行重新核算）");
				}
			}

		}else {
			return R.error("未查询该物流订单标记对应的物流订单信息");
		}


		//计算物流费用详情
		List<TccLogisticsDetailChannelFee> feeList = countLogisticsDetailFee(logisticsList);

		//根据发票号分组
		Map<String, List<TccLogisticsComprehensive>> groupsByStr = logisticsList.stream().collect(Collectors.groupingBy(e->e.getLogInvoiceNo()));
		//遍历
		groupsByStr.forEach((logInvoiceNo, listByInvoiceNo) -> {
			List<TccLogisticsDetailChannelFee> feeByInvoiceList = feeList.stream().filter(e->e.getLogInvoiceNo().equals(logInvoiceNo)).collect(Collectors.toList());;
			TccLogisticsDetailChannelFee feeInfo = feeByInvoiceList.get(0);
			//***物流发票计重（总） = 物流渠道费用详情内容
			BigDecimal logInvoiceWeight = feeInfo.getShipOrderWeight();
			//***物流发票费用（总） = 物流渠道费用详情内容
			BigDecimal logInvoiceCost = feeInfo.getLogisticsCost();

			List<TccFbaDeliverSon> tccFbaDeliverSonList = new ArrayList<>();
			for(TccLogisticsComprehensive item:listByInvoiceNo){
				//*** 物流发票箱数 = 箱号分类汇总--计数统计
				List<TccFbaDeliverSon> tccFbaDeliverSonListByOne = new TccFbaDeliverSon().setFbaDeliverItemId(item.getFbaDeliverItemId()).queryList();
				tccFbaDeliverSonList.addAll(tccFbaDeliverSonListByOne);
			}
			//按箱子编号去重
			//Map<String, List<TccFbaDeliverSon>> groupsByBoxNo = tccFbaDeliverSonList.stream().collect(Collectors.groupingBy(e->e.getBoxNo()));


			//*** 物流销售费用（总） = FBA发货单&实际物流费（总）之和
			BigDecimal logInvoiceSalesFee = BigDecimal.ZERO;
			//根据发货单号去重
			Map<String, List<TccLogisticsComprehensive>> groupsByDeliverBid = listByInvoiceNo.stream().collect(Collectors.groupingBy(e->e.getFbaDeliverBid()));
			//遍历，填入去重的信息
			List<TccLogisticsComprehensive> listByDeliverBid = new ArrayList<>();
			groupsByDeliverBid.forEach((k, v) -> listByDeliverBid.add(v.get(0)));
			for(TccLogisticsComprehensive item:listByDeliverBid){
				TccFbaFeeDetails tccFbaFeeDetails = new TccFbaFeeDetails().setSourceBid(item.getFbaDeliverBid()).queryFirst();//根据发货单号获取实际物流运费
				logInvoiceSalesFee = logInvoiceSalesFee.add(tccFbaFeeDetails.getPriceTranPredict());
			}

			//int logInvoiceBox = groupsByBoxNo.size();//物流发票箱数
			//*** 物流订单利润（总） = 物流销售费用（总）-物流发票费用（总）
			BigDecimal logOrderProfit = logInvoiceSalesFee.subtract(logInvoiceCost);
			BigDecimal logOrderProfitMargin = BigDecimal.ZERO;
			if(logInvoiceCost.compareTo(BigDecimal.ZERO)!=0){
				//*** 物流订单利润率（总） = 物流订单利润（总）/物流发票费用（总）*100%
				logOrderProfitMargin = (logOrderProfit.divide(logInvoiceCost,4,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)))
						.setScale(2, BigDecimal.ROUND_HALF_UP);//结果保留2位小数
			}else {
				throw new RuntimeException("计算有误，请核实");
			}

			//计算信息填入
			for(TccLogisticsComprehensive tccLogisticsComprehensive:listByInvoiceNo){
				tccLogisticsComprehensive.setLogOrderProfit(logOrderProfit);//物流订单利润（总）
				tccLogisticsComprehensive.setLogOrderProfitMargin(logOrderProfitMargin);//物流订单利润率（总）
				tccLogisticsComprehensive.setLogInvoiceWeight(logInvoiceWeight);//物流发票计重（总）
				tccLogisticsComprehensive.setLogInvoiceCost(logInvoiceCost);//物流发票费用（总）
				tccLogisticsComprehensive.setLogInvoiceSalesFee(logInvoiceSalesFee);//物流销售费用（总）

				tccLogisticsComprehensiveMapper.update(tccLogisticsComprehensive);
			}

		});



		return R.ok();
	}




	/**
	 * 按单收费核算取消
	 */
	@Override
	public R countCostCancel(String logisticsMarkingBid)throws Exception{
		//验证：
		List<TccLogisticsComprehensive> logisticsList = new TccLogisticsComprehensive()
				.setLogisticsMarkingBid(logisticsMarkingBid)
				.setStatus(TccLogisticsComprehensiveEnum.Status.GENERATED.value)
				.queryList();

		if(logisticsList!=null && logisticsList.size()>0){
			for(TccLogisticsComprehensive item:logisticsList){
				if(item.getFreightMethod().equals(TccLogisticsComprehensiveEnum.FreightMethod.BY_INVOICE.value)){
					return R.error("计算方式为：按物流发票，无需进行取消");
				}
				if(item.getLogInvoiceWeight()==null || item.getLogInvoiceWeight().compareTo(BigDecimal.ZERO)==0){
					return R.error("还未核算过，无需取消；");
				}
			}

		}else {
			return R.error("未查询该物流订单标记对应的物流订单信息");
		}

		//置空、置0
		for(TccLogisticsComprehensive item:logisticsList){
			item.setLogOrderProfit(BigDecimal.ZERO);//物流订单利润（总）
			item.setLogOrderProfitMargin(BigDecimal.ZERO);//物流订单利润率（总）
			item.setLogInvoiceWeight(BigDecimal.ZERO);//物流发票计重（总）
			item.setLogInvoiceCost(BigDecimal.ZERO);//物流发票费用（总）
			item.setLogInvoiceSalesFee(BigDecimal.ZERO);//物流销售费用（总）
			tccLogisticsComprehensiveMapper.update(item);

			//删除物流渠道费用详情，根据发票号
			storageMapper.delLogisticsDetailChannelFeeByLogInvoiceNo(item.getLogInvoiceNo());
			// 删除物流渠道详情，根据发票号
			storageMapper.delLogisticsChannelDetailByLogInvoiceNo(item.getLogInvoiceNo());
		}

		return R.ok();
	}





}
